6

Ich arbeite mit Db (über SQLite.NET PCL, nicht async Version). Im Moment habe ich eine listview mit einigen Daten (aus db), auch ich habe eine Suchleiste/Eintrag (seine nvm), wo Benutzer einige Werte eingeben können und dann über LINQ ich werde ein machen Abfrage und Aktualisierung SourceItems meiner Liste.Dynamisch suchen mit Interrupts, über Aufgaben C#

Also die Probleme mit der Leistung kommt, weil mein DB Millionen Platten bekam und einfach LINQ Abfrage arbeiten sehr slow.In anderen Worten, wenn der Benutzer einige Daten eingeben zu schnell, bekommt Anwendung riesige Lags und manchmal kann Absturz.
dieses Problem zu beheben, kommen einige Dinge in meinem Kopf (theoretisch Lösung):

1) Sie benötigen Methode zu setzen (was ich Abfrage in db machen) auf Aufgabe (zu meinem Haupt-UI-Thread) zu entsperren

2) initialisieren Timer, dann einschalten und:

  • wenn 1 Sekunde vergangen, dann => meine Methode (Abfrage) auf Aufgabe (ähnlich zu Hintergrund-Thread ausgeführt werden)
  • wenn 1 Sekunde nicht bestanden, dann verlassen Sie die anonyme Methode.

So ähnlich (oder ähnlich) oder irgendwelche Vorschläge. Danke!

UPD:
Also um ehrlich zu sein, habe ich versucht, zu viel und nur knapp sein Ziel ein gutes Ergebnis
erhalten BTW, meine aktuellen Code (Snippets):
1) Mein Suchmethode

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 (anonyme Methode)

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 

       }; 

Das Hauptproblem ist, wie man diesen Teil (mit diesen Fällen) implementiert, wo 1 Sekunde vergangen ist und nur dann mache ich Abfrage, um meine Liste zu aktualisieren (jedes Mal, wenn der Benutzer einen Wert in die Suchleiste eingibt) , dieser Trigger (Timer) muss sich wieder auf Null auffrischen).

Jede Hilfe wird geschätzt, danke!
PS Sorry für mein eng. Kompetenzen!

Antwort

3

Eine Möglichkeit, es zu tun ist, kombinieren async Task.Run und 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

Danke !! Genau was ich brauche, funktioniert gut. PS Aber wenn ich das erste Mal (etwas Wert in searchbar) eingeführt habe, bekomme ich eine Ausnahme (zB: runing auf Android-Gerät - Debug zeigt "AndroidRunTimeThrowException"), aber dann funktioniert gut, seltsame Glitch! – XTL

+0

Kein Problem. Ich benutze es in Android-Apps und bekomme keine Ausnahmen. Stellen Sie sicher, dass CancellationTokenSource cancellationTokenSource; ist auf der obersten Ebene der Klasse. –

+0

ja, seine globale Variable! Seltsam ... sehr seltsam :). Morgen krank nochmal nachschauen. Vielen Dank – XTL

1

Sie möchten warten, bevor Sie Ihre Suche tatsächlich durchführen. Das Killing einer Suchaufgabe kann zu undefiniertem Verhalten führen.

Sie möchten den aktuellen Suchfilter speichern und 1 Sekunde später erneut vergleichen. Wenn sich das nicht geändert hat, machen Sie die Suche.Andernfalls abbrechen:

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

Wie die Ansicht Modell auf dem Laufenden zu halten, bewegen Sie isBusy Zuweisungen innerhalb QueryToDB, denn das ist, wenn Ihr View-Modell wirklich besetzt ist:

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

    // do your search 

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

Thread.Sleep - ich denke, das für UI-Thread ist, nicht wahr? Danke für den Rat! – XTL