2016-01-30 3 views
7

Ho una funzionalità di utenti di ricerca. Ho fornito una vista testuale e su quella vista testo cambiato metodo Sto sparando un metodo per ottenere dati dal server web. Ma sto affrontando un problema quando l'utente digita la lettera, perché tutti gli hit API eseguiti in attività asincrone. Il servizio dovrebbe essere colpito dopo 100 milli-sec di attesa, significa che se l'utente digita una lettera "a" allora non digita per 100 milli-sec, quindi dobbiamo colpire il servizio. Ma se l'utente digita "a" allora "b" allora "c", quindi un servizio dovrebbe essere colpito per "abc", non per tutti.annullamento attività asincrona C# xamarin

Ho seguito il link ufficiale, ma non mi aiuta https://msdn.microsoft.com/en-us/library/jj155759.aspx

Quindi, in pratica qui è il mio codice

textview.TextChange+= (sender,e) =>{ 
    CancellationTokenSource cts = new CancellationTokenSource(); 
     await Task.Delay(500); 
     // here some where I have to pass cancel token 
     var lst = await APIClient.Instance.GetUserSearch("/user/get?searchTerm=" + newText, "application/json",cts); 
     if (lst != null && lst.Count > 0){ 
     lstSearch.AddRange(lst); 
     } 
    } 

Ecco il mio metodo per GetUser

public async Task<JResponse> GetUserSearch<JResponse>(string uri, string contentType,CancellationToken cts) 
    { 
     try 
     { 
      Console.Error.WriteLine("{0}", RestServiceBaseAddress + uri); 

      string url = string.Format("{0}{1}", RestServiceBaseAddress, uri); 

      var request = (HttpWebRequest)WebRequest.Create(url); 
      request.ContentType = contentType; 
      if (Utility.CurrentUser != null && !string.IsNullOrWhiteSpace(Utility.CurrentUser.AuthToken)) 
      { 
       request.Headers.Add("api_key", Utility.CurrentUser.AuthToken); 
      } 
      request.Method = "POST"; 

      var payload = body.ToString(); 

      request.ContentLength = payload.Length; 

      byte[] byteArray = Encoding.UTF8.GetBytes(body.ToString()); 
      request.ContentLength = byteArray.Length; 

      using (var stream = await request.GetRequestStreamAsync()) 
      { 
       stream.Write(byteArray, 0, byteArray.Length); 
       stream.Close(); 
      } 
      using (var webResponse = await request.GetResponseAsync()) 
      { 
       var response = (HttpWebResponse)webResponse; 
       using (var reader1 = new StreamReader(response.GetResponseStream())) 
       { 
        Console.WriteLine("Finished : {0}", uri); 
        var responseStr = reader1.ReadToEnd(); 
        var responseObj = JsonConvert.DeserializeObject<JResponse>(
         responseStr, 
         new JsonSerializerSettings() 
         { 
          MissingMemberHandling = MissingMemberHandling.Ignore, 
          NullValueHandling = NullValueHandling.Ignore 
         }); 
        return responseObj; 
       } 
      } 
     } 
     catch (System.Exception ex) 
     { 
      Utility.ExceptionHandler("APIClient", "ProcessRequestAsync", ex); 
     } 

     return default(JResponse); 
    } 
+0

Si dovrebbe guardare in Esempio [Estensioni reattiva (Rx)] (https://msdn.microsoft.com/data/gg577609). –

risposta

0

Try usare il timer. La prima volta poi cambi testo - lo crei. Quindi cambi testo dopo - riavvia il timer. Se non cambi il testo per 700 millisecondi, il timer attiva il metodo PerformeSearch. Utilizzare Timeout.Infinite per il parametro del periodo del timer per impedirne il riavvio.

textview.TextChange += (sender,e) => 
{ 
    if (_fieldChangeTimer == null) 
    _fieldChangeTimer = new Timer(delegate 
    { 
       PerformeSearch(); 
    }, null, 700, Timeout.Infinite); 
    else 
    { 
    _fieldChangeTimer.Change(700, Timeout.Infinite); 
    } 
}; 
6

Nel tuo esempio, si sta creando un CancellationTokenSource - è necessario mantenere un riferimento ad esso, in modo che la prossima volta che il gestore viene richiamato, la ricerca precedente può essere annullata. Here è un'app di console di esempio che dovrebbe essere in grado di eseguire, ma il pezzo importante è nel gestore.

private CancellationTokenSource _cts; 

private async void TextChangedHandler(string text) // async void only for event handlers 
{ 
    try 
    { 
     _cts?.Cancel();  // cancel previous search 
    } 
    catch (ObjectDisposedException)  // in case previous search completed 
    { 
    } 

    using (_cts = new CancellationTokenSource()) 
    { 
     try 
     { 
      await Task.Delay(TimeSpan.FromSeconds(1), _cts.Token); // buffer 

      var users = await _userService.SearchUsersAsync(text, _cts.Token); 
      Console.WriteLine($"Got users with IDs: {string.Join(", ", users)}"); 
     } 
     catch (TaskCanceledException)  // if the operation is cancelled, do nothing 
     { 
     } 
    } 
} 

Assicurarsi di passare il CancellationToken in tutte dei async metodi, inclusi quelli che eseguono la richiesta web, in questo modo si segnale l'annullamento fino al livello più basso.

0

Creare un'istanza di CancellationTokenSource.

cts = new CancellationTokenSource(); Metodo

private void cancelButton_Click(object sender, RoutedEventArgs e) 
{ 
    if (cts != null) 
    { 
     cts.Cancel(); 
    } 
}