Come eseguire il codice nel thread della GUI?

Come eseguire il codice nel thread della GUI?

Funziona bene per WPF con MVVM .

Application.Current.Dispatcher.Invoke(
    () =>
    {
         // Code to run on the GUI thread.
    });

Questo non funziona in modo coerente (fallirà se siamo all'interno di un gestore per le estensioni reattive):

Dispatcher.CurrentDispatcher.Invoke(
    () =>
    {
         // Fails if we are inside a handler for Reactive Extensions!
    });

Extra per esperti:il motivo?

In base alla progettazione, a qualsiasi thread può essere associato un thread del dispatcher, vedere MSDN:Dispatcher Class.

Se facciamo riferimento a Dispatcher.CurrentDispatcher da qualsiasi thread, creerà effettivamente un nuovo thread del dispatcher, che è separato dal thread del dispatcher dell'interfaccia utente WPF ufficiale. Quando proviamo a eseguire codice su questo thread del dispatcher appena creato, WPF verrà lanciato in quanto non è il thread del dispatcher dell'interfaccia utente ufficiale.

La soluzione è usare sempre Application.Current.Dispatcher.Invoke() o Application.Current.Dispatcher.BeginInvoke() . Vedi Qual è la differenza tra Invoke() e BeginInvoke().

Aggiornamento 2020-05-02:è possibile eseguire un'applicazione WPF con più thread del dispatcher dell'interfaccia utente WPF. Lavoro con un'enorme app WPF che sta facendo questo. È difficile farlo funzionare, ma una volta che funziona, è sorprendente e l'intera app viene eseguita un ordine di grandezza più velocemente poiché ci sono più thread del dispatcher dell'interfaccia utente. Felice di rispondere a domande su questo.

Testato su:

  • WPF
  • .NET 4.5
  • .NET 4.6
  • .NET 4.61

Per eseguire il extendedNotifyIcon_OnHideWindow metodo sul thread della GUI usa il Dispatcher come hai fatto per mostrarlo.

Thread threadToClosePopup = new Thread(new ThreadStart((Action)delegate() { 
  Thread.Sleep(1000); 
  txtLog.Dispatcher.Invoke(
    DispatcherPriority.Normal,
    (Action)() => extendedNotifyIcon_OnHideWindow());
}));

Questo ti darà il dispatcher della finestra:

Dispatcher.CurrentDispatcher

Finché lo ottieni sul thread di Windows.