wake-up-neo.com

Ändern Sie mit Dispatcher.Invoke WPF-Steuerelemente aus einem Nicht-Haupt-Thread

Ich habe vor kurzem mit dem Programmieren in WPF angefangen und bin auf folgendes Problem gestoßen. Ich verstehe nicht, wie man die Dispatcher.Invoke()-Methode verwendet. Ich habe Erfahrung im Threading und habe ein paar einfache Windows Forms - Programme erstellt, in denen ich gerade die

Control.CheckForIllegalCrossThreadCalls = false;

Ja, ich weiß, dass das ziemlich lahm ist, aber dies waren einfache Überwachungsanwendungen.

Tatsache ist, dass jetzt eine WPF-Anwendung erstellt wird, die Daten im Hintergrund abruft. Ich starte einen neuen Thread, um den Aufruf zum Abrufen der Daten (von einem Webserver) auszuführen. Jetzt möchte ich sie auf meinem WPF-Formular anzeigen. Die Sache ist, ich kann keine Kontrolle über diesen Thread festlegen. Nicht einmal ein Label oder irgendetwas. Wie kann das gelöst werden?

Antworten Sie auf Kommentare:
@ Jalfp:
Also verwende ich diese Dispatcher-Methode im 'neuen Profil', wenn ich die Daten erhalte? Oder sollte ich einen Hintergrundarbeiter veranlassen, die Daten abzurufen, in ein Feld einzufügen und einen neuen Thread zu starten, der wartet, bis dieses Feld gefüllt ist, und den Dispatcher anrufen, um die abgerufenen Daten in den Steuerelementen anzuzeigen?

64
D. Veloper

Als Erstes ist zu verstehen, dass der Dispatcher nicht dafür ausgelegt ist, lange Sperrvorgänge auszuführen (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. das Aktualisieren des Werts einer Fortschrittsleiste).

Sie können Ihre Daten in einem Hintergrund-Worker abrufen und die ReportProgress-Methode verwenden, um Änderungen im UI-Thread zu verbreiten.

Wenn Sie den Dispatcher wirklich direkt verwenden müssen, ist das ganz einfach:

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

japf hat es richtig beantwortet. Für den Fall, dass Sie sich mehrzeilige Aktionen anschauen, können Sie wie folgt schreiben.

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

Informationen für andere Benutzer, die Informationen zur Leistung erhalten möchten:

Wenn Ihr Code für eine hohe Leistung erforderlich ist, können Sie zunächst mit dem CheckAccess-Flag prü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 sie von Intellisense angezeigt wird. Beachten Sie, dass CheckAccess einen Performance-Overhead verursacht (Overhead in wenigen Nanosekunden). Es ist nur besser, wenn Sie die erforderliche Mikrosekunde speichern möchten, um den 'Aufruf' um jeden Preis durchzuführen. Außerdem gibt es immer die Möglichkeit, zwei Methoden zu erstellen (on with invoke und andere without), wenn die Methode sicher ist, ob sie sich im UI-Thread befindet oder nicht. Es ist nur selten der seltenste Fall, in dem Sie diesen Aspekt des Dispatchers betrachten sollten.

21
Yogee

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)));
0
Gopi Rao