tua app ha un main thread dell'interfaccia utente (di solito ManagedThreadId==1
). Tipicamente in un'app di chat i tuoi eventi arriveranno su altri thread (sia thread di ascolto socket dedicato o thread di thread thread dal codice di ascolto). Se si desidera aggiornare l'interfaccia utente da un evento che viene attivato su un altro thread, è necessario utilizzare il dispatcher. Un test utile qui è il metodo Dispatcher.CheckAccess()
che restituisce true se il codice è sul thread dell'interfaccia utente e false se in qualche altro thread. Una chiamata tipica sembra qualcosa di simile:
using System.Windows.Threading; // For Dispatcher.
if (Application.Current.Dispatcher.CheckAccess()) {
network_links.Add(new NetworkLinkVM(link, start_node, end_node));
}
else {
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(()=>{
network_links.Add(new NetworkLinkVM(link, start_node, end_node));
}));
}
Se siete nella finestra principale è possibile utilizzare:
Dispatcher.BeginInvoke(...
Se siete in someother contesto ad esempio, un modello di vista quindi utilizzare:
Application.Current.Dispatcher.BeginInvoke(
Invoke vs BeginInvoke
Usa Invoke
se si desidera che il thread corrente di aspettare fino a quando il thread UI ha elaborato il codice di spedizione o BeginInvoke
se si desidera che il thread corrente continui senza attendere il completamento dell'operazione sul thread dell'interfaccia utente.
MessageBox, Dispatcher e Invoke/BeginInvoke:
Dispatcher.Invoke
bloccano la discussione fino a quando la MessageBox è respinto.
Dispatcher.BeginInvoke
consentirà al codice thread di continuare a essere eseguito mentre il thread dell'interfaccia utente bloccherà la chiamata MessageBox fino alla sua rimozione.
CurrentDispatcher vs Current.Dispatcher!
Be ware di Dispatcher.CurrentDispatcher
poiché la mia comprensione di ciò è che restituirà un Dispatcher per il thread corrente non il thread dell'interfaccia utente. Generalmente sei interessato al dispatcher sul thread dell'interfaccia utente - Application.Current.Dispatcher
restituisce sempre questo.
Nota aggiuntiva:
Se si stanno trovando si trovano a dover controllare dispatcher CheckAccess spesso allora un metodo di supporto utile è:
public void DispatchIfNecessary(Action action) {
if (!Dispatcher.CheckAccess())
Dispatcher.Invoke(action);
else
action.Invoke();
}
che può essere chiamato come:
DispatchIfNecessary(() => {
network_links.Add(new NetworkLinkVM(link, start_node, end_node));
});
Quello dipende ... Su quale thread viene eseguito quel metodo? Inoltre, per sicurezza, stai usando WPF, giusto? ('Dispatcher' funziona solo con quello.) – svick
Quale framework UI stai usando?(WinForms, WPF o SL) Ci sono differenze tra loro –
Sì, come suggerisce lo svick, dipende dal fatto che stai toccando l'interfaccia utente da un altro thread (in modo asincrono) – gideon