![]() |
"Live-Suche" realisieren (hier: C#)
Hallo,
der folgende Code ist zwar in C# geschrieben, aber es handelt sich im Prinzip um ein grundlegendes Problem. Ich möchte beim Tippen in einer textBox "live" eine Liste von Einträgen durchsuchen. D.h. beim 1. Buchstaben beginnt die Suche. Das geht soweit auch. Wenn ich nun während der Suche weiter tippe, dann soll die laufende Suche abgebrochen und eine neue gestartet werden. Und genau da hapert's. Ich weiß nicht, wie ich das ohne Threads lösen kann (und mit erst recht nicht). Versucht habe ich es so ("IsSearching" und "cancelSearchProgress" sind jeweils mit "false" initialisiert):
Code:
Ich bekomme weder die Meldung "cancel" noch "canceled" zu Gesicht. Das Programm hängt in der While-Schleife.
// Aufruf im textBox-OnChange
myClass.StartSearch(); // relevanter Code der Methode StartSearch() public void StartSearch() { // start new search if (!this.isSearching) { this.Search(); } // stop currrent search and start a new one else { this.CancelSearchProgress(); // wait for the ending of the old search method while (this.isSearching) { Thread.Sleep(10); Application.DoEvents(); } MessageBox.Show("canceled"); // start new search this.Search(); } } // relevanter Code der Methode Search() private void Search() { this.isSearching = true; this.cancelSearchProgress = false; foreach ( /* ... */ ) { // cancel search progress if (this.cancelSearchProgress) { MessageBox.Show("cancel"); this.isSearching = false; break; } // ... Application.DoEvents(); } this.isSearching = false; // nachträglich ergänzt } Wo liegt mein Denkfehler? Grüße, Matze |
Re: "Live-Suche" realisieren (hier: C#)
Überlege dir mal den Fall, wenn du eine Suche startest, diese nicht abbrichst sondern fertig suchen lässt, und dann eine neue suche startest. Nach dem ersten Suchlauf ist this.isSearching immernoch true!
|
Re: "Live-Suche" realisieren (hier: C#)
Ich Dussel habe zu viel aus dem Code gekürzt. In Wirklichkeit setze ich "isSearching" nach der Schleife auf "false". Ich ergänze es oben. Sorry.
|
Re: "Live-Suche" realisieren (hier: C#)
Und in this.CancelSearchProgress(); setzt du this.CancelSearchProgress auf True? Ich weiß nicht, wie das in C# ist, aber bekommst du da eventuell Schwierigkeiten mit dem gleichen Namen?
|
Re: "Live-Suche" realisieren (hier: C#)
Ja, genau das mache ich. Da C# case-sensitive ist, dürfte das nichts ausmachen.
Edit: "cancelSearchProgress" wird korrekt auf "true" gesetzt, denn in der While-Schleife ist diese variable "true". |
Re: "Live-Suche" realisieren (hier: C#)
Der erste Aufruf von Search ruft DoEvents auf, welches bei einem weiteren Tastendruck wiederum StartSearch aufruft. Das springt in den else-Teil und wartet auf das Ende des ersten Aufrufs. Auf das Ende einer Methode, die weiter unten auf dem Callstack liegt, kann man im gleichen Thread allerdings lange warten :zwinker: .
Code:
Mit etwas Umstrukturieren (genauer: Durch Iteratoren Coroutines simulieren... :mrgreen:) könnte man das Problem leicht lösen, aber wenn es deiner Anwendung nützt, würde ich direkt zu asynchroner Verarbeitung greifen.
StartSearch()
-> DoEvents() --> Search() ---> while (isSearching) ... -> isSearching = false; Mit der TPL von .NET 4.0 gar kein Problem :love: ... bis dahin sollte es aber auch so funktionieren:
Code:
Ob das design-technisch optimal ist, will ich gerade lieber nicht beurteilen, denn über Design in Verbindung mit asynchronem Code musste ich mir bis jetzt noch nie Gedanken machen. Außerdem bin ich davon ausgegangen, dass deine Suchanfragen nicht so teuer sind, dass laufende Anfragen unbedingt abgebrochen werden müssen, wenn die nächste gestartet ist.
object currentToken;
public void StartSearch() { var token = new object(); this.currentToken = token; ThreadPool.QueueUserWorkItem(delegate { var result = Search(...); // In den UI-Thread wechseln SynchronizationContext.Current.Send(delegate { if (token == currentToken) // Ergebnis verwerfen, wenn schon die nächste Anfrage gestartet wurde this.OnSearchCompleted(result); }, null); }); } |
Re: "Live-Suche" realisieren (hier: C#)
Erstmal vielen Dank!
Ich bin nur gerade leicht überfordert, muss ich zugeben. Was ist bei dir denn "this.OnSearchCompleted"? Ist das eine Methode, die aufgerufen wird, wenn zu Ende gesucht wurde? Zitat:
Die Suchergebnisse habe ich bisher in eine Liste in der Klasse eingetragen. Die bleibt nun leer, wenn ich von außen darauf zugreifen möchte. Also so ist das wohl nichts. Grüße |
Re: "Live-Suche" realisieren (hier: C#)
Zitat:
Code:
Du wirst dieses Pattern auch in vielen .NET-Klassen wie Ping finden, weshalb es einen eigenen Namen trägt: EAP,
public class SearchDingens
{ public void SearchAsync(); public event EventHandler<YourResultEventArgs> SearchCompleted; //public void CancelAsync(); } ![]() Zitat:
Code:
, da dann aber mehrere Threads auf currentToken zugreifen, solltest du synchronisieren:
token == currentToken
Code:
(Mal sehen, wann der erste mit einer Interlocked-Lösung kommt :mrgreen: ...)
object lockObj = new object();
void Search(object token) { foreach (...) { lock (lockObj) if (token == currentToken) return; ... } } public void StartSearch() { var token = new object(); lock (lockObj) this.currentToken = token; ... } Edit: Die kanonische On-Methode:
Code:
void OnEventX(YourEventArgs args)
{ EventHandler<YourEventArgs> handler = this.EventX; if (handler != null) handler(this, args); } |
Re: "Live-Suche" realisieren (hier: C#)
Das ist wirklich nett, dass du dir so viel zeit für deine Beiträge nimmst, um mir zu helfen, danke. Aber ich kann damit überhaupt nichts anfangen.
Ich werde wohl auf die Live-Suche verzichten müssen. :( Edit: Es geht nun, vielen Dank. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:16 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz