Ich habe vor kurzem mit der Programmierung in WPF begonnen und bin auf das folgende Problem gestoßen. Ich verstehe nicht, wie man die Dispatcher.Invoke()
Methode benutzt. Ich habe Erfahrung im Threading und habe ein paar einfache Windows Forms-Programme erstellt, in denen ich gerade das verwendet habe
Control.CheckForIllegalCrossThreadCalls = false;
Ja, ich weiß, dass das ziemlich lahm ist, aber das waren einfache Überwachungsanwendungen.
Tatsache ist, dass ich jetzt eine WPF-Anwendung erstelle, die Daten im Hintergrund abruft. Ich starte einen neuen Thread, um den Aufruf zum Abrufen der Daten (von einem Webserver) durchzuführen. Jetzt möchte ich sie in meinem WPF-Formular anzeigen. Die Sache ist, ich kann keine Kontrolle über diesen Thread einstellen. Nicht einmal ein Etikett oder so. Wie kann das gelöst werden?
Antwortkommentare:
@Jalfp:
Also verwende ich diese Dispatcher-Methode im 'neuen Profil', wenn ich die Daten erhalte? Oder sollte ich einen Hintergrundmitarbeiter veranlassen, die Daten abzurufen, in ein Feld einzufügen und einen neuen Thread zu starten, der wartet, bis dieses Feld ausgefüllt ist, und den Dispatcher anrufen, um die abgerufenen Daten in den Steuerelementen anzuzeigen?
quelle
Antworten:
Das erste ist zu verstehen, dass der Dispatcher nicht für lange Blockierungsvorgänge ausgelegt ist (z. B. das Abrufen von Daten von einem WebServer ...). Sie können den Dispatcher verwenden, wenn Sie eine Operation ausführen möchten, die im UI-Thread ausgeführt wird (z. B. Aktualisieren des Werts eines Fortschrittsbalkens).
Sie können Ihre Daten in einem Hintergrund-Worker abrufen und mithilfe der ReportProgress-Methode Änderungen im UI-Thread weitergeben.
Wenn Sie den Dispatcher wirklich direkt verwenden müssen, ist dies ziemlich einfach:
Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Background, new Action(() => this.progressBar.Value = 50));
quelle
new Action(...)
.BeginInvoke
und stattdessen der Compilerfehler CS1660 ausgegeben wird.japf hat es richtig beantwortet. Nur für den Fall, dass Sie mehrzeilige Aktionen betrachten, können Sie wie folgt schreiben.
Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Background, new Action(() => { this.progressBar.Value = 50; }));
Informationen für andere Benutzer, die mehr über die Leistung erfahren möchten:
Wenn Ihr Code für eine hohe Leistung geschrieben werden muss, können Sie zunächst mithilfe des CheckAccess-Flags überprüfen, ob der Aufruf erforderlich ist.
if(Application.Current.Dispatcher.CheckAccess()) { this.progressBar.Value = 50; } else { Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Background, new Action(() => { this.progressBar.Value = 50; })); }
Beachten Sie, dass die Methode CheckAccess () in Visual Studio 2015 ausgeblendet ist. Schreiben Sie sie einfach, ohne zu erwarten, dass Intellisense sie anzeigt. Beachten Sie, dass CheckAccess einen Overhead für die Leistung hat (Overhead in wenigen Nanosekunden). Es ist nur dann besser, wenn Sie die Mikrosekunde sparen möchten, die erforderlich ist, um den Aufruf um jeden Preis durchzuführen. Es gibt auch immer die Möglichkeit, zwei Methoden zu erstellen (on mit Aufruf und andere ohne), wenn der Aufruf der Methode sicher ist, ob sie sich im UI-Thread befindet oder nicht. Es ist nur der seltenste Fall, wenn Sie sich diesen Aspekt des Dispatchers ansehen sollten.
quelle
Wenn ein Thread ausgeführt wird und Sie den Haupt-UI-Thread ausführen möchten, der vom aktuellen Thread blockiert wird, verwenden Sie Folgendes:
aktueller Thread:
Dispatcher.CurrentDispatcher.Invoke(MethodName, new object[] { parameter1, parameter2 }); // if passing 2 parameters to method.
Haupt-UI-Thread:
Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Background, new Action(() => MethodName(parameter)));
quelle
Die obige @ japf-Antwort funktioniert einwandfrei und in meinem Fall wollte ich den Mauszeiger von einem sich drehenden Rad zurück auf den normalen Pfeil ändern, sobald der CEF-Browser das Laden der Seite beendet hat. Falls es jemandem helfen kann, hier ist der Code:
private void Browser_LoadingStateChanged(object sender, CefSharp.LoadingStateChangedEventArgs e) { if (!e.IsLoading) { // set the cursor back to arrow Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => Mouse.OverrideCursor = Cursors.Arrow)); } }
quelle