C# – Invoke required durch Lambda Ausruck verschönert

Passiert mir immer mal wieder. Ich versuche die Inhalte eines Controls aus einem anderen Thread heraus zu verändern als aus dem, der das Control urpsrünglich mal erzeugte. Was dabei heraus kommt ist klar: The calling thread cannot access this object because it is owned by another thread. Ich muss also folglich meinen Code im Kontext des Threads ausführen, der das Control erstellte. Bis dato nutzte ich immer folgendes Snippet:

this.Dispatcher.Invoke(
    new Action(
        delegate()
        {
            // Do your code here
            MessageBox.Show("Invoke succeeded");
        }
    )
);

Wann immer dieser Codeblock erreicht wird, werden die folgenden Anweisungen im Kontext des UI-Threads ausgeführt. Das klappte bisher immer ganz gut und ich nutzte es z.B. immer dann wenn ich Debug-Meldungen zu meinem Debug-Listener-Dialog sandte. Leider scheint diese Methode ziemlich „teuer“ zu sein. Als ich heute einmal an einem langsameren Rechner arbeitete und mehrere Debugmeldungen pro Sekunde absetzte, ging die Performance des Programms doch stark in die Knie. Ein kurzes Profiling sprach Bände, Invoke ist schweinelahm, besonders wenn es, wie in diesem Fall gar nicht notwendig gewesen wäre. Zum Glück gibt es für WPF die Möglichkeit für jedes Control das Feld InvokeRequired abzufragen welches angibt, ob sich die Programmausführung gerade in dem Thread befindet, der das Control erstellt hat. Somit könnte ich also folgenden Code ausführen:

if (this.Dispatcher.CheckAccess())
{
    // Your Invoked Code
}
else
{
    // Your code without invoking
}

Das funktioniert zwar, aber ich müsste ja meinen Code zweimal tippen und pflegen…unschön. Zur Lösung des Problemchens entschied ich mich für Lambda-Ausdrücke, denn so konnte ich meinen Code in einer Variablen zwischenspeichern.

// Create a function with a string input and a bool return value
Func<string,bool> handleEvent = (string pMessage) =>
{
	MessageBox.Show(pMessage);
	return true;
};                

// Are we running on the correct UI Thread
if (this.Dispatcher.CheckAccess())
{
	//Directly run the method
	handleEvent(pMessage);
}
else
{
	// Invoke the method from the UI Thread dispatcher
	this.Dispatcher.Invoke(handleEvent,pMessage);
}

Jetzt läuft es so wie ich es mir vorstelle. Verschönern, Verkürzen und Modularisieren kann man natürlich immernoch.

Done;

Kolja Engelmann

Technikfan, Freizeitprogrammierer, selbsternannter Toolking und vermutlich größter Drachenfan Deutschlands blogged hier die Lösungen zu IT-Problemen die ihm über den Weg laufen, kleine Softwaretools, nostalgische Anfälle und missbraucht das Ganze gern auch mal als privates Tagebuch und Fotoalbum.

Das könnte dich auch interessieren …

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert