2009-10-29 13 views
60

Niedawno rozpocząłem programowanie w WPF i wpadłem na następujący problem. Nie rozumiem, jak korzystać z metody Dispatcher.Invoke(). Mam doświadczenie w gwintowania i zrobiłem kilka prostych programów Windows Forms, gdzie po prostu korzystałem zZmiana sterowania WPF z wątku innego niż główny za pomocą Dispatcher.Invoke

Control.CheckForIllegalCrossThreadCalls = false; 

Tak wiem, że to dość kiepski ale były proste aplikacje monitorujące.

Faktem jest, że robię aplikację WPF, która pobiera dane w tle, zaczynam nowy wątek, aby wykonać wywołanie pobierania danych (z serwera WWW), teraz chcę wyświetlić go na moim WPF Formularz. Chodzi o to, że nie mogę ustawić żadnej kontroli z tego wątku. Nie ma nawet etykiety ani niczego. Jak można to rozwiązać?

odpowiedzi komentarzy:
@Jalfp:
więc skorzystać z tej metody Dyspozytor w „nowym bieżniku” kiedy uzyskać dane? Czy powinienem zrobić, aby pracownik działający w tle odzyskał dane, umieścił je w polu i uruchomił nowy wątek, który czeka, aż to pole zostanie wypełnione i wywoła dyspozytora, aby pokazać pobrane dane do formantów?

Odpowiedz

145

Pierwszą rzeczą jest zrozumienie tego, że Dispatcher nie jest zaprojektowany do uruchamiania długich operacji blokowania (takich jak pobieranie danych z WebServera ...). Możesz użyć Dispatchera, jeśli chcesz uruchomić operację, która będzie wykonywana w wątku UI (np. Aktualizując wartość paska postępu).

Co można zrobić, to pobrać dane w tle w tle i użyć metody ReportProgress do propagowania zmian w wątku interfejsu użytkownika.

Jeśli naprawdę trzeba użyć dyspozytora bezpośrednio, to jest całkiem prosta:

Application.Current.Dispatcher.BeginInvoke(
    DispatcherPriority.Background, 
    new Action(() => this.progressBar.Value = 50)); 
+19

Można pozbyć się „nowego działania (” strony, a po prostu użycie wyrażenia lambda: DispatcherPriority.Background,() => this.progressBar.Value = 50 – jrista

+0

Tak nie wiem dlaczego ja położyć Akcja tutaj: p – japf

+0

Więc używam tej metody Dispatchera w "nowym bieżniku", kiedy otrzymuję dane? Lub powinienem zrobić, że pracownik tła pobierze dane, umieści je w polu i rozpocznie nowy wątek, który czeka, aż to pole zostanie wypełnić i zadzwonić do dyspozytora, aby pokazać pobrane dane do kontroli? –

19

japf ma odpowiedzieć poprawnie. Na wszelki wypadek, jeśli patrzysz na akcje wieloliniowe, możesz napisać jak poniżej.

Application.Current.Dispatcher.BeginInvoke(
    DispatcherPriority.Background, 
    new Action(() => { 
    this.progressBar.Value = 50; 
    })); 

Informacja dla innych użytkowników, którzy chcą wiedzieć o wydajności:

Jeśli kod muszą być napisane pod kątem wysokiej wydajności, można najpierw sprawdzić, czy Invoke jest wymagane przy użyciu CheckAccess flagę.

if(Application.Current.Dispatcher.CheckAccess()) 
{ 
    this.progressBar.Value = 50; 
} 
else 
{ 
    Application.Current.Dispatcher.BeginInvoke(
     DispatcherPriority.Background, 
     new Action(() => { 
     this.progressBar.Value = 50; 
     })); 
} 

Należy zauważyć, że metoda CheckAccess() jest ukryte z Visual Studio 2015, więc po prostu napisać go nie oczekując intellisense, aby pokazać go. Należy zauważyć, że CheckAccess ma narzut wydajności (obciążenie w kilka nanosekund). Jest to tylko lepsze, gdy chcesz zaoszczędzić mikrosekundę wymaganą do wykonania "invoke" za wszelką cenę. Poza tym zawsze istnieje opcja utworzenia dwóch metod (on z invoke i innych bez), gdy wywołanie metody jest pewne, czy jest w wątku UI, czy nie. To rzadki przypadek, kiedy powinieneś spojrzeć na ten aspekt dyspozytora.

Powiązane problemy