Modifica i controlli WPF da un thread non principale utilizzando Dispatcher.Invoke

Recentemente ho iniziato a programmare in WPF e ho riscontrato il seguente problema. Non capisco come usare il metodo Dispatcher.Invoke() . Ho esperienza nel threading e ho creato alcuni semplici programmi Windows Form in cui ho appena usato il

 Control.CheckForIllegalCrossThreadCalls = false; 

Sì, lo so che è piuttosto zoppo, ma queste erano semplici applicazioni di monitoraggio.

Il fatto è che ora sto facendo un’applicazione WPF che recupera i dati in background, avvio un nuovo thread per effettuare la chiamata per recuperare i dati (da un server web), ora voglio visualizzarli sul mio modulo WPF. Il fatto è che non posso impostare alcun controllo da questo thread. Neanche un’etichetta o niente. Come può essere risolto?

Rispondi ai commenti:
@Jalfp:
Quindi uso questo metodo di Dispatcher nel “nuovo battistrada” quando ottengo i dati? O dovrei fare in modo che un lavoratore in background recuperi i dati, li metta in un campo e inizi un nuovo thread che aspetta che questo campo venga riempito e chiama il dispatcher per mostrare i dati recuperati nei controlli?

La prima cosa è capire che, il Dispatcher non è progettato per eseguire operazioni di blocco lunghe (come il recupero di dati da un WebServer …). È ansible utilizzare il Dispatcher quando si desidera eseguire un’operazione che verrà eseguita sul thread dell’interfaccia utente (ad esempio, l’aggiornamento del valore di una barra di avanzamento).

È ansible recuperare i dati in un worker in background e utilizzare il metodo ReportProgress per propagare le modifiche nel thread dell’interfaccia utente.

Se hai davvero bisogno di usare direttamente il Dispatcher, è piuttosto semplice:

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

japf ha risposto correttamente. Nel caso in cui si guardi alle azioni su più righe, è ansible scrivere come di seguito.

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

Informazioni per altri utenti che desiderano conoscere le prestazioni:

Se è necessario scrivere il codice per prestazioni elevate, è ansible innanzitutto verificare se è richiesto il richiamo utilizzando il flag CheckAccess.

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

Si noti che il metodo CheckAccess () è nascosto da Visual Studio 2015, quindi è sufficiente scriverlo senza aspettarsi che intellisense lo mostri. Si noti che CheckAccess ha un sovraccarico sulle prestazioni (sovraccarico in pochi nanosecondi). È solo meglio quando vuoi salvare quel microsecondo richiesto per eseguire il “richiamo” ad ogni costo. Inoltre, c’è sempre un’opzione per creare due metodi (on con invoke, e altri without) quando il metodo di chiamata è sicuro se è in UI Thread o no. È raro che rari casi in cui si dovrebbe guardare questo aspetto del dispatcher.