AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein "Live-Suche" realisieren (hier: C#)
Thema durchsuchen
Ansicht
Themen-Optionen

"Live-Suche" realisieren (hier: C#)

Ein Thema von Matze · begonnen am 16. Dez 2009 · letzter Beitrag vom 16. Dez 2009
Antwort Antwort
Benutzerbild von Matze
Matze
(Co-Admin)

Registriert seit: 7. Jul 2003
Ort: Schwabenländle
14.929 Beiträge
 
Turbo Delphi für Win32
 
#1

"Live-Suche" realisieren (hier: C#)

  Alt 16. Dez 2009, 17:31
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:
// 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
}
Ich bekomme weder die Meldung "cancel" noch "canceled" zu Gesicht. Das Programm hängt in der While-Schleife.
Wo liegt mein Denkfehler?

Grüße, Matze
  Mit Zitat antworten Zitat
dominikkv

Registriert seit: 30. Sep 2006
Ort: Gundelfingen
1.109 Beiträge
 
Delphi 2007 Professional
 
#2

Re: "Live-Suche" realisieren (hier: C#)

  Alt 16. Dez 2009, 17:46
Ü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!
Dominik
Wer anderen eine Grube gräbt, hat ein Gruben-Grab-Gerät!
  Mit Zitat antworten Zitat
Benutzerbild von Matze
Matze
(Co-Admin)

Registriert seit: 7. Jul 2003
Ort: Schwabenländle
14.929 Beiträge
 
Turbo Delphi für Win32
 
#3

Re: "Live-Suche" realisieren (hier: C#)

  Alt 16. Dez 2009, 17:49
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.
  Mit Zitat antworten Zitat
dominikkv

Registriert seit: 30. Sep 2006
Ort: Gundelfingen
1.109 Beiträge
 
Delphi 2007 Professional
 
#4

Re: "Live-Suche" realisieren (hier: C#)

  Alt 16. Dez 2009, 18:05
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?
Dominik
Wer anderen eine Grube gräbt, hat ein Gruben-Grab-Gerät!
  Mit Zitat antworten Zitat
Benutzerbild von Matze
Matze
(Co-Admin)

Registriert seit: 7. Jul 2003
Ort: Schwabenländle
14.929 Beiträge
 
Turbo Delphi für Win32
 
#5

Re: "Live-Suche" realisieren (hier: C#)

  Alt 16. Dez 2009, 18:06
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".
  Mit Zitat antworten Zitat
Benutzerbild von Khabarakh
Khabarakh

Registriert seit: 18. Aug 2004
Ort: Brackenheim VS08 Pro
2.876 Beiträge
 
#6

Re: "Live-Suche" realisieren (hier: C#)

  Alt 16. Dez 2009, 18:43
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 .

Code:
StartSearch()
-> DoEvents()
--> Search()
---> while (isSearching) ...
-> isSearching = false;
Mit etwas Umstrukturieren (genauer: Durch Iteratoren Coroutines simulieren... ) könnte man das Problem leicht lösen, aber wenn es deiner Anwendung nützt, würde ich direkt zu asynchroner Verarbeitung greifen.

Mit der TPL von .NET 4.0 gar kein Problem ... bis dahin sollte es aber auch so funktionieren:
Code:
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);
   });
}
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.
Sebastian
Moderator in der EE
  Mit Zitat antworten Zitat
Benutzerbild von Matze
Matze
(Co-Admin)

Registriert seit: 7. Jul 2003
Ort: Schwabenländle
14.929 Beiträge
 
Turbo Delphi für Win32
 
#7

Re: "Live-Suche" realisieren (hier: C#)

  Alt 16. Dez 2009, 18:57
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 von Khabarakh:
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.
Wieso teuer? Langsam ist es halt, wenn ich das bei jedem Buchstaben zu Ende suchen lasse.

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
  Mit Zitat antworten Zitat
Benutzerbild von Khabarakh
Khabarakh

Registriert seit: 18. Aug 2004
Ort: Brackenheim VS08 Pro
2.876 Beiträge
 
#8

Re: "Live-Suche" realisieren (hier: C#)

  Alt 16. Dez 2009, 19:47
Zitat von Matze:
Was ist bei dir denn "this.OnSearchCompleted"? Ist das eine Methode, die aufgerufen wird, wenn zu Ende gesucht wurde?
Genau. Ein On-Präfix kennzeichnet unter .NET eine Methode, die ein zugehöriges Event auslöst - im Zusammenhang mit Delphi natürlich etwas verwirrend . Da du die Klasse ja anscheinend unabhängig von der Form machen (wie es sich gehört ), dieser aber wahrscheinlich die Synchronisierung lieber abnehmen willst, bietet sich dieses Pattern an:
Code:
public class SearchDingens
{
    public void SearchAsync();
    public event EventHandler<YourResultEventArgs> SearchCompleted;
    //public void CancelAsync();
}
Du wirst dieses Pattern auch in vielen .NET-Klassen wie Ping finden, weshalb es einen eigenen Namen trägt: EAP, Event-based Asynchronous Pattern.

Zitat von Khabarakh:
Wieso teuer? Langsam ist es halt, wenn ich das bei jedem Buchstaben zu Ende suchen lasse.
Gut, wenn es erkennbare Auswirkungen hat, dass eine alte Anfrage unnötigerweise fertig rechnet, dann musst du in meinen Vorschlag eben doch noch ein Cancellation-Konzept einfügen. Deine Abbruchbedingung in Search wäre dann der Vergleich
Code:
token == currentToken
, da dann aber mehrere Threads auf currentToken zugreifen, solltest du synchronisieren:
Code:
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;
    ...
}
(Mal sehen, wann der erste mit einer Interlocked-Lösung kommt ...)


Edit: Die kanonische On-Methode:
Code:
void OnEventX(YourEventArgs args)
{
   EventHandler<YourEventArgs> handler = this.EventX;
   if (handler != null)
      handler(this, args);
}
Sebastian
Moderator in der EE
  Mit Zitat antworten Zitat
Benutzerbild von Matze
Matze
(Co-Admin)

Registriert seit: 7. Jul 2003
Ort: Schwabenländle
14.929 Beiträge
 
Turbo Delphi für Win32
 
#9

Re: "Live-Suche" realisieren (hier: C#)

  Alt 16. Dez 2009, 20:33
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.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:20 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz