6

Sto lavorando con Db (tramite SQLite.NET PCL, versione non asincrona). Al momento attuale ho una listview con alcuni dati (presi da db), ho anche una barra di ricerca/voce (la sua nvm), dove l'utente può inserire alcuni valori e poi, tramite LINQ ho intenzione di fare un interrogazione e aggiornamento SourceItems della mia lista.Ricerca dinamica con interrupt, tramite Attività C#

Così i problemi viene fornito con le prestazioni, perché il mio DB ottenuto milione di dischi e semplici LINQ di query lavorando molto slow.In altre parole, quando l'utente entra troppo veloci alcuni dati, applicazione ottiene enormi ritardi e possono a volte Crash.
Per risolvere questo problema, alcune cose vengono in mente (teoricamente soluzione):

1) Necessità di mettere il metodo (che io faccio query in db) sul compito (per sbloccare il mio thread dell'interfaccia utente principale)

2) Inizializzare il timer, quindi accendere e:

  • se uno secondo passò, poi => Esegui il mio metodo (query) sul compito (simile a thread in background)
  • se uno secondo non lo fa superato, quindi esci dal metodo anonimo.

Qualcosa del genere (simile) o qualsiasi suggerimento. Grazie!

UPD:
Quindi, per essere onesti, ho provato troppo e non ha ancora ottenere un buon risultato
BTW, il mio codice corrente (Frammenti):
1) Il mio SearchMethod

public void QueryToDB(string filter) 
     { 
      this.BeginRefresh(); 

      if (string.IsNullOrWhiteSpace (filter)) 
      { 
       this.ItemsSource = SourceData.Select(x => x.name); // Source data is my default List of items 
      } 
      else 
      { 
       var t = App.DB_Instance.FilterWords<Words>(filter); //FilterWords it's a method,where i make direct requests to the database 
       this.ItemsSource = t.Select(x => x.name); 
      } 
      this.EndRefresh(); 
     } 

2) Searchbar.TextChanged (metodo anonimo)

searchBar.TextChanged +=async (sender, e) => 
       { 
        ViewModel.isBusy = true; //also i got a indicator,to show progress,while query working 
        await Task.Run(()=> //my background,works fine 
        { 
         listview.QueryToDB(searchBar.Text); 
        }); 
        ViewModel.isBusy = false; // after method is finished,indicator turn off 

       }; 

Il problema principale è come implementare questa parte (con questi casi), dove è passato 1 secondo e solo allora ho intenzione di fare una query per aggiornare il mio sourceItems dell'elenco (ogni volta, quando l'utente inserisce un valore nella barra di ricerca , questo trigger (timer) deve aggiornare nuovamente a zero).

Qualsiasi aiuto sarà apprezzato, grazie!
PS Ci scusiamo per il mio ing. abilità!

risposta

3

Un modo per farlo è quello di coniugare async Task.Run e CancellationTokenSource:

CancellationTokenSource cancellationTokenSource; 

searchView.TextChanged += async (sender, e) => 
{ 
    if (cancellationTokenSource != null) cancellationTokenSource.Cancel(); 
    cancellationTokenSource = new CancellationTokenSource(); 
    var cancellationToken = cancellationTokenSource.Token; 

    var searchBar = (sender as SearchBar); 
    if (searchBar != null) 
    { 
     string searchText = searchBar.Text; 
     try 
     { 
      await Task.Delay(650, cancellationToken); 

      if (cancellationToken.IsCancellationRequested) return; 

      var searchResults = await Task.Run(() => 
      { 
       return ViewModel.Search(searchText); 
      }); 

      if (cancellationToken.IsCancellationRequested) return; 

      ViewModel.YouItems.Repopulate(searchResults); 
     } 
     catch (OperationCanceledException) 
     { 
      // Expected 
     } 
     catch (Exception ex) 
     { 
      Logger.Error(ex); 
     } 
    } 
}; 
+0

Grazie !! Esattamente quello che mi serve, funziona bene. PS Ma quando si introduce la prima volta (un po 'di valore nella barra di ricerca), ottengo un'eccezione (ad esempio: esecuzione su dispositivo Android - mostra debug "AndroidRunTimeThrowException"), ma poi funziona bene, strano problema tecnico! – XTL

+0

Nessun problema. Lo uso su app Android e non ottengo eccezioni. Assicurati di CancellazioneTokenSource cancellationTokenSource; è al livello più alto della classe. –

+0

sì, la sua variabile globale! Strano ... molto strano :). Domani malato di nuovo. Grazie – XTL

1

Si desidera attendere prima di eseguire effettivamente la ricerca. Uccidere un'attività di ricerca a metà strada può causare un comportamento indefinito.

Si desidera salvare il filtro di ricerca corrente e confrontarlo di nuovo 1 secondo dopo. Se ciò non è cambiato, fai la ricerca.In caso contrario, interrompere:

searchBar.TextChanged += async (sender, e) => 
{ 
    var filter = searchBar.Text; 
    await Task.Run(() => 
    { 
     Thread.Sleep(1000); 
     if (filter == searchBar.Text) 
      listview.QueryToDB(searchBar.Text); 
    }); 
}; 

da mantenere il modello di vista aggiornata, muovere le isBusy incarichi all'interno QueryToDB perché è quando il tuo modello di vista è davvero occupato:

public void QueryToDB(string filter) 
{ 
    this.BeginRefresh(); 
    ViewModel.isBusy = true; 

    // do your search 

    ViewModel.isBusy = false; 
    this.EndRefresh(); 
} 
+0

Thread.Sleep - credo che questo è per il thread UI, no? Grazie per il consiglio! – XTL