Suchfunktion - funktioniert mit Einschränkungen


Memfis

Erfahrenes Mitglied
Ich hatte die nun folgende Frage letzte Woche noch zurückgehalten, weil ich der Meinung war, dass sich die Antwort in meinem Buch finden würde, dass ich mit extra für C# und .net gekauft habe, aber leider ist dem nicht so. Es geht darum, dass ich den Thread so lange laufen lassen möchte, bis der "Stop"-Button gedrückt wird. Leider wird in dem Buch aber alles so erklärt, dass jeder Knopf eine Aktion durchführt, also der Programmcode immer so beginnt:

C#:
        private void cmdStop_Click(object sender, EventArgs e)
        {

        }
Wenn ich da ein t.abort(); einsetze wird das logischerweise nicht erkannt. Nun wollte ich das abkürzen und habe kurzerhand das gemacht:

C#:
        private void cmdSuchen_Click(object sender, EventArgs e)
        {
            listView1.Items.Clear();
            string path = cmbLaufwerk.Text;
            string searchPattern = "*" + txtSuchbegriff.Text + "*";

                System.Threading.Thread t = new System.Threading.Thread(delegate() { Search(path, searchPattern); });
                t.Start();
                if ((bool)cmdStop_Click == true)
                {
                    t.Abort();
                }
        }

Egal wie ich es drehe und wende. Ich bekomme es nicht hin, dass der "Stop"-Button eine Funktion übernehmen kann, weil es jedes mal falsch sein soll. Habe auch Varianten wie diese probiert (und zahlreiche andere), aber das wird so nix.

C#:
                if ((bool)cmdStop.Click = true)

Ansonsten wäre das Tool fertig. Kleine Bugs habe ich behoben (Wie beispielsweise Klammerfehler der dazu führte, dass immer *.doc-Dokumente gefunden wurden, selbst wenn es nicht angehakt war)
 

rd4eva

Erfahrenes Mitglied
Also ich weiß wie man Performance mist und wenn der Zeitstamp es auf einem RL Server mehrfach so wieder gibt denke ich stimmt das schon
Sowohl reine Logik als auch meine Testergebnisse sagen was anderes.

Egal wie ich es drehe und wende. Ich bekomme es nicht hin, dass der "Stop"-Button eine Funktion übernehmen kann, weil es jedes mal falsch sein soll. Habe auch Varianten wie diese probiert (und zahlreiche andere), aber das wird so nix
Selbst wenn man das: (bool)cmdStop_Click == true so schreiben könnte (was man nicht kann) stellt sich die Frage:
Wie sollte das Funktionieren?
Versuch dir doch einfach mal den Ablauf des Programms vorzustellen.
Der Thread wird gestartet, es wird geprüft ob stop == true.
Wenn ja: Brich den Thread ab.
Wenn Nein. Mache garnix.

Das wars. Die Prüfung ob stop==true wird genau ein einziges Mal durchgeführt.

Ich hatte dir bereits Links gepostet wo du nachschauen kannst wie es richtig geht.
 

Memfis

Erfahrenes Mitglied
Du hast natürlich recht. Völliger Blödsinn was ich da machen wollte und an welcher Stelle. Ich habe es nun (denke ich) an der richtigen Stelle, aber ich weis eben nicht, wie ich den Thread jetzt überprüfen kann. t.start() kann ich nicht mitnehmen und auch andere Versuche schlugen fehl. Das Beispiel habe ich durchgelesen.

C#:
        private void Search(string path, string searchPattern)
        {
            try
            {
[...]
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            bool cmdStop = false;
            if ((bool)cmdStop == true)
            {
                t.Abort();
            }
Irgendwie muss ich das "t" mitnehmen, aber genau das funktioniert nicht.

Edit: Habe eben noch etwas ausprobiert.
C#:
            bool cmdStop = false;
            if ((bool)cmdStop == true)
            {
                System.Threading.Thread.ResetAbort();
            }

C#:
            while ((bool)cmdStop == true)
            {
                System.Threading.Thread.ResetAbort();
            }
Aber auch das funktioniert nicht. Irgendwie drehe ich mich im Kreis.

Edit 2: Damit komme ich der Sache wohl schon näher. Allerdings stürzt das Programm dabei ab.
C#:
        private void cmdStop_Click(object sender, EventArgs e)
        {
            System.Threading.Thread.ResetAbort();
        }
 
Zuletzt bearbeitet:

rd4eva

Erfahrenes Mitglied
Dein Problem ist doch ganz einfach das du an den Thread bzw. die Variable nicht "ran kommst".
Es gibt zig Möglichkeiten das Problem zu lösen und die einfachste wäre vermutlich die Variable zu einem Class Member (Field) zu machen.

Hier ein ganz einfaches Beispiel.:

C#:
public class Foo
    {
        //Ein Field
        private Thread t;
                
        private void Bar()
        {
            //Das Field Initialisieren
            t = new Thread();
        }

        private void DoSth()
        {
            //Auf das Field zugreifen
            t.Start();
        }
    }
 
Zuletzt bearbeitet:

Memfis

Erfahrenes Mitglied
Das Beispiel verstehe ich leider nicht. Das geht schon damit los, "private Thread t" als Fehler erkannt wird.
Der Typ- oder Namespacename "Thread" konnte nicht gefunden werden. (Fehlt eine Using-Direktive oder ein Assemblyverweis?)
Kannst du das Beispiel konkretisieren, ohne gleich den fertigen Code für mein Programm zu posten? Ich finde es schon gut, wenn ich das Beispiel selber für mein Tool anpassen muss, denn abschreiben kann jeder und so muss ich zumindest noch ein bisschen mitdenken und lerne es hoffentlich dabei.

Außerdem würde ich am Ende der Suche gerne noch die Meldung ausgeben, dass die Suche abgeschlossen ist, aber egal, wo ich mein "MessageBox.Show("Die Suche wurde abgeschlossen");" hinpacke, es wird nach jedem Schleifendurchlauf angezeigt (oder auch gar nicht). Vermutlich muss hier wieder ein extra-Befehl her, aber "finally" ist es nicht.


Mal ganz nebenbei gefragt: Ist so ein Suchprogramm wie es hier im Thread behandelt wird ein eher einfaches Programm, dass man als Anfänger problemlos selber lösen können sollte oder doch schon eine größere Nummer? Ich meine ohne die großzügige Hilfe deinerseits wäre ich wohl längst nicht so weit, hätte noch nicht einmal die Suchoption fertig.
 
Zuletzt bearbeitet:

rd4eva

Erfahrenes Mitglied
Der Typ- oder Namespacename "Thread" konnte nicht gefunden werden. (Fehlt eine Using-Direktive oder ein Assemblyverweis?)
1. Wenn man mit solchen Fehlern nichts anfangen dann hilft google einem 100% weiter. Du bist schließlich nicht der erste dem ein Compiler Fehler um die Ohren geworfen wird.
Der Fehler bedeutet (in deinem Fall) das dir eine using Direktive fehlt. Nämlich using System.Threading;.

Kannst du das Beispiel konkretisieren, ohne gleich den fertigen Code für mein Programm zu posten? Ich finde es schon gut, wenn ich das Beispiel selber für mein Tool anpassen muss, denn abschreiben kann jeder und so muss ich zumindest noch ein bisschen mitdenken und lerne es hoffentlich dabei.
Das Beispiel war schon extrem einfach und sollte dir nur zeigen was ein Field einer Class ist. Du musst es also definitiv anpassen.
Lass mich versuchen es dir an einem PHP Beispiel zu erklären da du dich in PHP ja anscheinend auskennst.

Was du Bisher machst ist ungefähr folgendes
PHP:
Class MyClass{
	
	public function MyFirstFunction(){
		$var = "foobar";
	}
	
	public function MySecondFunction(){
		echo $var;
	}	
}

$class = new MyClass();
$class->MyFirstFunction();
$class->MySecondFunction();
Hier ist das c# Äquivalent
C#:
class MyClass
    {
        public void MyFirstFunction()
        {
            string var = "foobar";
        }

        public void MySecondFunction()
        {
            Console.Write(var);
        }
    }
Du erstellst eine neue Klasse.
Du führst die Methode MyFirstFunction aus ( in deinem Fall wäre das die cmdSuchen_Click Methode).
Diese Methode setzt eine Variable hier $var und weist ihr einen Wert zu. ( In deinem Fall ist $var = System.Threading.Thread t denn t ist auch nur eine Variable die einen Wert hält)
Und jetzt führst du die zweite Methode MySecondFunction aus ( in deinem Fall wäre das cmdStop_Click)
Die Methode MySecondFunction versucht jetzt auf die Variable $var zuzugreifen die von MyFirstFunction erstellt wurde. ( Du versuchst von cmdStop_Click auf t zuzugreifen welches von cmdSuchen_Click erstellt wurde)
Und genau hier liegt das Problem, denn der Zugriff auf eben diese Variable ist nicht möglich.
MySecondFunction kennt die Variable überhaupt nicht und kann somit auch nicht auf sie zugreifen. (Das Stichwort in diesem Zusammenhang heißt Scope)

Damit nun also MySecondFunction auf die Variable zugreifen kann müssen wir sie in einen Bereich legen in dem sie von allen beiden Methoden aus erreichbar ist.
Und so würde es dann funktionieren:
PHP:
Class MyClass{
	
	public $var;
	
	public function MyFirstFunction(){
		$this->var = "foobar";
	}
	
	public function MySecondFunction(){
		echo $this->var;
	}	
}

$class = new MyClass();
$class->MyFirstFunction();
$class->MySecondFunction();
Und hier das gleiche in c#
C#:
class MyClass
    {
        public string var;

        public void MyFirstFunction()
        {
            this.var = "foobar";
        }

        public void MySecondFunction()
        {
            Console.Write(this.var);
        }
    }

Sehr viel einfacher kann ich es nun nicht mehr erklären.

Außerdem würde ich am Ende der Suche gerne noch die Meldung ausgeben, dass die Suche abgeschlossen ist, aber egal, wo ich mein "MessageBox.Show("Die Suche wurde abgeschlossen");" hinpacke, es wird nach jedem Schleifendurchlauf angezeigt (oder auch gar nicht). Vermutlich muss hier wieder ein extra-Befehl her, aber "finally" ist es nicht.
Eins nach dem anderen. Versuch erstmal zu verstehen was du bisher getan hast.
Und mit verstehen meine ich wirklich verstehen und nicht "ach ist ja toll, das funktioniert ja.".

Mal ganz nebenbei gefragt: Ist so ein Suchprogramm wie es hier im Thread behandelt wird ein eher einfaches Programm, dass man als Anfänger problemlos selber lösen können sollte oder doch schon eine größere Nummer? Ich meine ohne die großzügige Hilfe deinerseits wäre ich wohl längst nicht so weit, hätte noch nicht einmal die Suchoption fertig.
Die Suche an sich ist eher leichte Kost.
Das schwere ist das Multithreading auf das du (im nachhinein betrachtet) vielleicht erstmal verzichten solltest.

Abschließend hier noch ein Link der dir evtl. weiterhilft:
http://www.guidetocsharp.de/
 

Memfis

Erfahrenes Mitglied
Also dein kleines Beispiel habe ich problemlos verstanden, aber ich bekomme es nicht in mein Projekt übertragen. In deinem Beispiel geht es nur um eine Variable, die in der ersten Funktion einen Wert zugewiesen bekommt und in der zweiten Funktion wird dieser Wert dann abgerufen bzw. ausgegeben. Soweit also kein Problem.

Ich habe also eine Klasse für meine Funktion erstellt. So:
C#:
        class SystemThreading
        {
            public string t = new System.Threading.Thread(delegate() { Search(path, searchPattern); });
        }
Jetzt meckert C# wegen "path" und "searchPattern". Das kann ich noch nachvollziehen. Also habe ich folgendes gemacht:

C#:
        class SystemThreading
        {
            public string path = cmbLaufwerk.Text;
            public string searchPattern = "*" + txtSuchbegriff.Text + "*";

            public string t = new System.Threading.Thread(delegate() { Search(path, searchPattern); });
        }
Jetzt meckert C# zusätzlich noch wegen "cmbLaufwerk"und "txtSuchbegriff". Auch das kann ich noch irgendwie nachvollziehen, weil die Klasse ja noch nirgends bekannt ist. Also habe ich versucht genau das zu machen:
C#:
        private void cmdSuchen_Click(object sender, EventArgs e)
        {
            listView1.Items.Clear();
            
            public void test()
            {
                t.Start(SystemThreading);
            }
        }
Zur allgemeinen Erheiterung habe ich jetzt aus anfänglich 3 Fehlern (Beim ersten der Klasse) geschlagene 18 Fehler gemacht und bin am Ende. Wie soll das funktionieren?

Edit: Ich bin so durcheinander, dass ich zuletzt versehentlich einen völlig unsinnigen Code gepostet hatte. Ich meine, dieser hier ist nicht besser, aber meiner Ansicht nach wenigstens nachvollziehbar ;) Mit ein bisschen Glück ist es ja nur noch ein kleiner Fehler mit großer Wirkung.

Mit dem Code lehne ich mich an deinem Beispiel an. Unlogisch bleibt noch, warum der Name der Funktion (in deinem Fall das "MyFirstFunction" und "MySecondFunction" keine weitere Bedeutung haben soll) Ich habe dahingehend experimentiert und mal mehr, mal weniger Fehler erhalten. Die Lösung war jedenfalls nicht darunter.
 
Zuletzt bearbeitet:

Memfis

Erfahrenes Mitglied
Ich weis, dass ich eigentlich schon viel zu viel Hilfe in Anspruch genommen habe, aber es wäre auch schade, dass das Tool jetzt an der nicht vorhandenen "Stop"-Funktion scheitern würde, bzw. keine Meldung ausgegeben wird, wenn alle Verzeichnisse durchsucht wurden. Vielleicht erbarmt sich der ein oder andere noch?
 

Shakie

Erfahrenes Mitglied
Ich habe den Thread nicht verfolgt - er war mir zu lang :) . Ab welchem Post sollte ich lesen um rd4eva abzulösen und dir bei der Stop-Funktion zu helfen?
 

rd4eva

Erfahrenes Mitglied
Danke Shakie, bin gerade etwas ausgelastet.

In #21 / #23 sollte klar werden wo sein Problem liegt.
#24 / #26 sind eigentlich nur Grundlagen Erklärungen von mir und zielen nicht speziell auf sein Problem ab.
 

Shakie

Erfahrenes Mitglied
Memfis, du musst unterscheiden zwischen "Deklaration einer Variable" und "einer Variable einen Wert zuweisen".
Wenn du dir die Beispielklasse von rd4eva anschaust, dann steht da:
C#:
class MyClass
    {
        public string var;
    ...
Und nicht
C#:
class MyClass
    {
        public string var = "foobar";
    ...
Das erste Beispiel deklariert die Variable lediglich, Zweites weist ihr zusätzlich noch einen Wert zu.
Momentan verwendest du die zweite Version: du deklarierst eine System.Threading.Thread-Variable und weist ihr einen Wert zu, nämlich den Wert
C#:
new System.Threading.Thread(delegate() { Search(path, searchPattern); })
Dieser Wert wird der Variable zugewiesen, sobald die Klasse instanziiert wird!
Der Benutzer hat zu diesem Zeitpunkt deine Form wahrscheinlich noch gar nicht in voller Pracht zu Gesicht bekommen.
Wenn du aber lediglich die Thread-Variable deklarierst, ohne ihr einen Wert zuzuweisen, sollte es keine Compiler-Fehler geben:
C#:
class SystemThreading
{
	public System.Threading.Thread t;
}
Den Wert weist du der Variable erst dann zu, wenn der Benutzer auf den Button "Suche starten" geklickt hat, also bevor du "t.Start()" aufrufst.
 
Zuletzt bearbeitet:

Memfis

Erfahrenes Mitglied
Danke Shakie,

ich war diese (und letzte) Woche bisschen anderweitig beschäftigt, werde deinen Tipp aber bis spätestens zum Wochenende ausprobiert haben. Ich melde mich dann noch mal.
 

Forum-Statistiken

Themen
272.355
Beiträge
1.558.614
Mitglieder
187.830
Neuestes Mitglied
hansmeiser