2011-10-20 11 views
16

Sto creando un client di chat e non sono sicuro al 100% su come utilizzare dispatcher. Quindi la domanda è che ho un metodo in quanto tale:Utilizzo del C# Dispatcher

public void LostConnection() 
{ 
    myGUI.chatBox.AppendText("Lost connection to room: "+ myGUI.UsernameText.ToString() + "\r\n"); 
} 

Devo surrond la dichiarazione entro (myGUI.chatBox...) con un Dispatcher.Invoke? Apprezzo qualsiasi aiuto.

+0

Quello dipende ... Su quale thread viene eseguito quel metodo? Inoltre, per sicurezza, stai usando WPF, giusto? ('Dispatcher' funziona solo con quello.) – svick

+1

Quale framework UI stai usando?(WinForms, WPF o SL) Ci sono differenze tra loro –

+0

Sì, come suggerisce lo svick, dipende dal fatto che stai toccando l'interfaccia utente da un altro thread (in modo asincrono) – gideon

risposta

68

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)); 
}); 
+0

Hey ragazzi, scusate non ho specificato, sì è un'applicazione wpf e sì è cross threading. Sto impostando il delegato nel back-end che avvisa il mio modello che chiamerà quindi il metodo del dispatcher e aggiornerà l'interfaccia gui. Non ho ancora un'opzione con intellesense per aggiungere un dispatcher ma cercherò di forzarlo e vedere se funziona. Grazie ragazzi! Qualche altro consiglio? – Tombo890

+0

Se è stato incluso l'utilizzo dell'istruzione e si utilizza Application.Current.Dispatcher, si dovrebbe ottenere un risultato. Se il tuo "back-end" è in una dll, dovrai passare il Dispatcher del thread dell'interfaccia utente al tuo oggetto in modo che possa fare riferimento a esso. – Ricibob

+0

@Ricibob, solo per essere nitpicky, penso che il thread dell'interfaccia utente non debba sempre avere l'Id di 1. – svick

2

Qualcosa di simile (la parte superiore della mia testa) dovrebbe funzionare:

public void LostConnection() 
{ 
    myGUI.Invoke 
     ((MethodInvoker)delegate 
    { 
     myGUI.chatBox.AppendText("Lost connection to room: "+ myGUI.UsernameText.ToString() + "\r\n"); 
    }); 
} 
+0

Questo sarebbe in WinForms. Questa domanda apparentemente riguarda WPF. – svick

+1

Sì. Non era ovvio dalla domanda. –