Beschreibung:
Das Problem bei Threads ist, dass nicht einfach auf das Form zugegriffen werden kann. Normalerweise möchte man aber nach dem Ende eines Threads die verarbeiteten Informationen anzeigen. Der Dispatcher vereinfacht dies erheblich. Das System funktioniert über callbacks, ähnlich wie bei javascript üblich. Die callbacks können daher inline definiert werden und haben zugriff auf den Zustand der Methode in der sie definiert werden.
Aufruf (mit inline funktionen):
C#-Code: |
Dispatcher.Dispatch(
delegate(object[] args){System.Threading.Thread.Sleep(10000);args[0]="test";},
delegate(object[] args){labelTest.Text=(string)args[0];},
new object[]{null});
|
Was macht das
Die erste delegate wird asynchron in einem Thread aufgerufen. Die 10 Sekunden Wartedauer beeinflussen nicht die Anwendung.
Die zweite delegate wird aufgerufen, wenn die erste vorbei ist. Die Argumente sind für beide delegates das selbe Array, der erste Aufruf kann also Parameter in den zweiten Aufruf übergeben.
der zweite Aufruf ist immer synchron zum GUI Thread, sofern mindestens ein Form existiert.
Sollte keins existieren (or SYNCHRONIZE direktive ist nicht gesetzt) dann wird die delegate ebenfalls asynchron aufgerufen, dies macht Sinn für Konsolenanwendungen.
Der object-Parameter dient dazu, Argumente zu übergeben. Der Index muss definiert werden (wenn auch null). Verändern der array werte wird jeweils auf der Referenz ausfegührt, deshalb benötigen Stream.Read Aufrufe auch kein "ref" Schlüsselwort. Das selbe Prinzip wird hier ausgenutzt. Der parameter wird an beide callbacks übergeben.
Der obige Aufruf geht davon aus, dass der Aufruf in einem Form mit einem "labelTest" ausgeführt wird
Abhängigkeiten
Läuft unter .NET 2.0. Ist SYNCHRONIZE definiert, dann wird eine Referenz auf System.Windows.Forms benötigt.
Verwendungszwecke
- Hintergrundaufgaben einfach planen und ausführen.
- Events zeitverzögert von Form B nach Form A senden, z.B. wenn Form A eine liste mit einträgen enthält und Form B eine Bestätigung zum verarbeiten aller Einträge einholt, kann A benachrichtigt werden, wenn die Operation abgeschlossen ist.
- Asynchrones I/O. z.B. bei Socket.BeginConnect.
- Wrapper für beliebige klassen die keine synchronen callbacks anbieten oder nicht asynchron arbeiten. (Thread, Socket, TcpListener, Console.In,Out,Err).
C#-Code: |
#define SYNCHRONIZE
using System.Threading;
#if SYNCHRONIZE
using System.Windows.Forms;
#endif
namespace Dispatch
{
public delegate void DispatchHandler(object[] args);
public static class Dispatcher
{
public static Thread Dispatch(DispatchHandler Method, DispatchHandler Callback, params object[] Args)
{
Thread T = new Thread(delegate()
{
bool called = false;
Method(Args);
#if SYNCHRONIZE
for (int i = 0; i < Application.OpenForms.Count && !called; i++)
{
if (!Application.OpenForms[i].IsDisposed)
{
called = true;
Application.OpenForms[i].Invoke(Callback, Args);
}
}
#endif
if (!called)
{
Callback.Invoke(Args);
}
});
T.Start();
return T;
}
}
}
|
Mögliche Anpassungen
- Ermöglichen, dass der DispatchHandler einen Rückgabewert haben kann.
- Ändern des generischen "params object[]" in ein geeigneteres Format.
Schlagwörter: dispatcher, synchron, thread, threads, callback