2015-02-10 13 views
12

Ten fragment kodu pochodzi z Stephen Cleary's blog i podaje przykład sposobu zgłaszania postępu podczas korzystania z Task.Run. Chciałbym wiedzieć, dlaczego nie ma problemów z wieloma wątkami przy aktualizacji interfejsu użytkownika, przez co rozumiem, dlaczego wywołanie nie jest wymagane?Aktualizacje zadań Task.Run i UI

private async void button2_Click(object sender, EventArgs e) 
{ 
    var progressHandler = new Progress<string>(value => 
    { 
     label2.Text = value; 
    }); 
    var progress = progressHandler as IProgress<string>; 
    await Task.Run(() => 
    { 
     for (int i = 0; i != 100; ++i) 
     { 
      if (progress != null) 
       progress.Report("Stage " + i); 
      Thread.Sleep(100); 
     } 
    }); 
    label2.Text = "Completed."; 
} 
+0

@newbieguy powiązań, smyczkowe wywołuje metodę toString() automatycznie –

Odpowiedz

19

Progress<T> łapie prąd SynchronisationContext gdy jest tworzony. Za każdym razem, gdy wywołujesz Report, sekretnie przekazuje to do przechwyconego kontekstu. W tym przykładzie przechwycony kontekst jest interfejsem użytkownika, co oznacza, że ​​nie występują żadne wyjątki.

+0

Wiesz co gwint pierwszeństwo mają do tego?tj: Normalny, Tło, Czas aplikacji itp. – Kelly

+0

@Klauzula priorytet wysyłającego jest Zwykła. Zobacz sekcję uwag tutaj https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatchersynchronizationcontext.post(v=vs.110).aspx – Gusdor

8

Konstruktor Progress<T> oddaje aktualny SynchronizationContext obiekt.

Klasa SynchronizationContext jest obiektem wyodrębniająca dane z zaangażowanych modelu gwintowania. Oznacza to, że w Windows Forms użyje Control.Invoke w WPF będzie korzystał Dispatcher.Invoke itp

Gdy obiekt progress.Report nazywa, sam obiekt Progress wie, że należy go uruchomić za pomocą swojego delegata przechwycony SynchronizationContext.

Innymi słowy działa, ponieważ Progress został zaprojektowany, aby poradzić sobie z tym bez konieczności wyraźnego wypowiadania przez programistę.

4

Wydaje się, że jesteś zmieszany ze względu na fakt, że część tej maszyny cross-wątek jest ukryte przed oczami deweloperskich tak po prostu trzeba „wziąć i użyć”: http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis.aspx

wprowadziliśmy do interfejsu IProgress umożliwia utworzenie doświadczenia dla wyświetlania postępów. Ten interfejs udostępnia metodę Report (T) , którą zadanie asynchroniczne wywołuje w celu zgłaszania postępu. Narażasz ten interfejs na sygnaturę metody asynchronicznej, a wywołujący musi dostarczyć obiekt, który implementuje ten interfejs. Wspólnie zadanie i wywołujący tworzą bardzo użyteczne powiązanie (i mogą być uruchomione na różnych wątkach ).

Mamy również klasę postępu, który jest implementacją IProgress. Zachęca się użytkownika do korzystania z funkcji Postęp w implementacji , ponieważ obsługuje ona wszystkie operacje dotyczące zapisywania i przywracania kontekstu synchronizacji. Postęp ujawnia zarówno zdarzenie , jak i wywołanie zwrotne czynności, które są wywoływane, gdy zadanie zgłasza postęp. Ten wzór umożliwia napisanie kodu, który po prostu reaguje na zmiany postępu w momencie ich wystąpienia. Razem, IProgress i Postęp umożliwiają łatwe przekazywanie informacji o postępie z zadania tła do wątku interfejsu użytkownika.

Jeszcze jedno wspomnieć: zgłoszenie postęp zostanie wywołany po część pracy jest wykonywana, nie tylko w tym momencie. Tak więc, jeśli twój wątek UI jest bezczynny i masz zapasowy rdzeń procesora, opóźnienie będzie prawie zerowe. Jeśli twój wątek interfejsu użytkownika jest zajęty, powiadomienie nie zostanie wywołane do momentu powrotu wątku interfejsu użytkownika (bez względu na to, ile wolnych rdzeni procesora ma twój komputer).

Powiązane problemy