Jeder der schon mal mit Threads gearbeitet hat kennt das Problem: Eine länger dauernde Berechnung wird in einen Thread ausgelagert und natürlich soll der Benutzer regelmäßig über den Fortgang der Berechnung informiert werden. Das geht aber nicht aus dem Arbeitsthread, da Controls nur über den eigenen UI-Thread heraus aktualisiert werden können.
Eine Alternative ist der Backroundworker aus dem .NET-Framework. Der erhöht aber nicht gerade die Code-Lesbarkeit und zerstückelt eine zusammenhängenden Codeblock in mehrere Einzelfunktionen.
Es gibt dafür jedoch auch eine elegante Lösung:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace WindowsApplication8
{
static class Program
{
[STAThread]
static void Main()
{
Application.Run(new TheForm());
}
public class TheForm : Form
{
Label label1;
Button button1;
public TheForm()
{
label1 = new System.Windows.Forms.Label();
label1.Location = new System.Drawing.Point(102, 14);
label1.Size = new System.Drawing.Size(130, 13);
button1 = new System.Windows.Forms.Button();
button1.Location = new System.Drawing.Point(12, 9);
button1.Size = new System.Drawing.Size(75, 23);
button1.Text = "Start";
button1.Click += new System.EventHandler(this.button1_Click);
Controls.AddRange(new Control[] { label1, button1 });
}
private void button1_Click(object sender, EventArgs e)
{
// Nimmt sich ein Thread und ruft damit DoIt auf
System.Threading.ThreadPool.QueueUserWorkItem(DoIt);
}
private void DoIt(object dummy)
{
int i = 1;
bool Cancel = false;
while (Cancel == false)
{
// Zu Demozwecken immer 1 Sekunde Pause
System.Threading.Thread.Sleep(1000);
// Dies ist sogenannter generischer Delegate,
// innerhalb des Blocks vollen Zugriff auf die
// UI zuläßt
MethodInvoker LabelUpdate = delegate
{
// Innerhalb dieses Blocks können Controls
// und Forms angesprochen werden, neue Fenster
// erzeugt werden etc....
label1.Text = i.ToString() + " Durchläufe absolviert";
};
Invoke(LabelUpdate);
if (i % 5 == 0)
{
MethodInvoker QuestionDelegate = delegate
{
// Sogar Rückfragen sind möglich
if (MessageBox.Show("Noch eine Runde ?", "Frage", MessageBoxButtons.YesNo) == DialogResult.No)
Cancel = true;
};
Invoke(QuestionDelegate);
}
i++;
}
}
}
}
}
Abgelegt unter
Multithreading,
backroundworker,
illegal cross calls,
thread,
threads,
UI,
Threadsicher,
delegate,
backgroundworker,
anonym,
anonyme,
delegates,
InvokeRequired,
threadübergreifend,
invoke,
CrossThreadException.
5 Kommentare zum Snippet