Najszybszy(?) sposób na aktualizację UI z innego wątku
... czyli Kochamy Delegaty, Wyrażenia Lambda i Extension Methods :)
Pisząc aplikacje Windows nie raz i nie dwa zdarza się, że musimy zaktualizować zawartość interfejsu użytkownika z poziomu innego wątku (który np. wykonuje jakieś obliczenia lub wykonuje długotrwałą operację). Niestety nie możemy tego zrobić bezpośrednio przez ustawienie odpowiednich właściwości w kodzie. Spróbujmy w oddzielnym wątku ustawić tytuł formularza:
1: private void button1_Click(object sender, EventArgs e)
2: {
3: var asyncCode = new Thread(() => Text = "Ala ma kota") { IsBackground = true };
4: asyncCode.Start();
5: }
W efekcie otrzymamy elegancki wyjątek:
Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on.
(dodatkowo widać, jak wyrażenia lambda upraszczają nasz kod - w tym przypadku wykonanie operacji asynchronicznie)
Cóż, trzeba to jakoś naprawić. W tym celu zrobimy sobie Extension Method, którego będziemy mogli używać na wszystkich obiektach dziedziczących z klasy Form.
1: public delegate void AsyncMethodInvoker();
2:
3: public static class FormAsyncUpdateExtension
4: {
5: public static void AsyncUpdate(this Form form, AsyncMethodInvoker asyncDelegate)
6: {
7: if(form.InvokeRequired)
8: {
9: form.Invoke(asyncDelegate);
10: }
11: else
12: {
13: asyncDelegate();
14: }
15: }
16: }
W linii pierwszej definiujemy delegata, który nam się dalej przyda (wiem wiem, mamy we Frameworku gotowy identyczny delegat
MethodInvoker, ale przykładów nigdy za wiele). A zaraz potem używamy go do zdefiniowania metody rozszerzającej klasę
Form.
Od tej pory będziemy mogli pisać kod typu:
moj_formularz.AsyncUpdate(() => moj_formularz.Text = "Ala ma kota");. Sprawdźmy:
1: private void button1_Click(object sender, EventArgs e)
2: {
3: var asyncCode =
4: new Thread(() =>
5: this.AsyncUpdate(() => Text = "Ala ma kota"))
6: { IsBackground = true };
7: asyncCode.Start();
8: }
Działa! Czy ktoś zna metodę, która po napisaniu raz, jest potem jeszcze zgrabniejsza w użyciu?