Mit einem Thread die Form aktualisieren
-
Hallo
Ich bingerade dabei mich in das Thema Threads einzuarbeiten. Nun habe ich es geschaftt per "button_klick" verschiedene Threads zu starten (diese sollen Später mal eine TCP Verbindung aufbauen). Ähnlich zu diesem Beispiel:
public class MyThread { public static void Thread1() { for (int i = 0; i < 10; i++) { Console.WriteLine("Thread1 {0}", i); } } public static void Thread2() { for (int i = 0; i < 10; i++) { Console.WriteLine("Thread2 {0}", i); } } } public class MyClass { public static void Main() { Console.WriteLine("Before start thread"); Thread tid1 = new Thread(new ThreadStart(MyThread.Thread1 ) ); Thread tid2 = new Thread(new ThreadStart(MyThread.Thread2 ) ); tid1.Start(); tid2.Start(); } }
Nun möchte ich aber innerhalb des Threads zum beispiel ein Textfeld innerhalb meiner Form beschreiben.
Wie mache ich sowas am besten?
Beste Grüße
-
Du kannst z. B. deinem Thread-Objekt eine Referenz auf eine TextBox o. ä. mitgeben. Wichtig ist dabei allerdings, dass du nicht direkt aus deinem Thread ein WinForms-Control manipulierst
, denn GUI-Elemente dürfen nur von dem Thread manipuliert werden, von dem sie erstellt wurden. Ein Control bietet hierfür die Methode Invoke an, welche einen Delegate mit dem entsprechenden manipulierenden Code übernimmt. Der Delegate wird dann auf dem Ersteller-Thread des Controls ausgeführt.
-
Außerdem musst du darauf achten, dass andere Threads erst dann auf deine Form-Controls zugreifen, wenn die Form erstellt wurde und nicht mehr darauf zugreifen, wenn sie geschlossen wird.
In deinem Beispiel werden die Threads unabhängig von einer Form gestartet, sodass es schwierig wird, sie mit ihr zu synchronisieren. Du hast aber geschrieben, dass du die Threads per Button-Click starten willst, d. h. zu dem Zeitpunkt ist deine Form schon mal einsatzbereit. Du musst dann noch darauf achten, dass die Threads auch beendet werden bzw. nicht mehr auf Controls zugreifen, wenn deine Form geschlossen wird.
Schau' dir auch mal BackgroundWorker an, vielleicht eignet der sich ja auch für deinen Einsatzzweck.
-
-
Hallo
Vielen dank für die Antworten.
Prinzipiell ist der Backgroundworker was ich suche.
Mein eigentliches Grundproblem, dass ich aus der DoWork Methode zugreifen möchte habe ich auch gelöst. Mit invoke, wie folgt:
private void button1_Click(object sender, EventArgs e) { // start backgroundWorker1 if (backgroundWorker1.IsBusy != true) { backgroundWorker1.RunWorkerAsync(); } } // Backgroundworker 1 private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { int a = 17; int b = 99; int c = 107; c = a + b; // write in Textbox from GUI by using invoke if (textBox3.InvokeRequired) { textBox3.Invoke((MethodInvoker)delegate {textBox3.Text = "xyy"; }); } }
Wie gesagt: Funktionieren tut es. ABer ich verstehe noch nicht so richtig warum.
Durch das InvokeRequired frage ich ob das Handle auf die Textbox zu meinem Thread gehört. Soweit so gut. Aber dann? Was genau macht .Invoke, der MethodInvoker und das delegate genau?Beste Grüße
ThreadAnfänger
-
Invoke führt das übergebene Delegat im GUI-Thread aus, und zwar synchron*. D.h. Dein Backgroundworker-Thread wird so lange blockiert, bis Invoke zurückkehrt. Ein Aufruf von Invoke ist auch relativ teuer.
Also wenn Du Tonnen von Berechnungen in einem Thread ausführst solltest Du nicht ständig versuchen die GUI zu aktualisieren, nur zu geschickt gewählten Zeitpunkten. Ein Mensch nimmt sowieso nicht so viele Änderungen pro Zeit wahr.* Es gibt auch noch BeginInvoke zu asynchronen Ausführung