web-dev-qa-db-fra.com

Utilisation du répartiteur C #

Je crée un client de chat et je ne suis pas sûr à 100% sur la façon d'utiliser le dispatcher. La question est donc que j'ai une méthode en tant que telle:

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

Dois-je remettre la déclaration dans (myGUI.chatBox... ) avec un Dispatcher.Invoke? J'apprécie toute aide.

22
Tombo890

Votre application possède un thread d'interface utilisateur principal (généralement ManagedThreadId==1). Généralement, dans une application de chat, vos événements arriveront sur d'autres threads (soit des threads d'écoute de socket dédiés, soit des threads de pool de threads à partir du code d'écoute). Si vous souhaitez mettre à jour l'interface utilisateur à partir d'un événement qui est tiré sur un autre thread, vous devez utiliser le répartiteur. Un test utile ici est la méthode Dispatcher.CheckAccess() qui retourne true si le code est sur le thread d'interface utilisateur et false si sur un autre thread. Un appel typique ressemble à quelque chose comme:

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

Si vous êtes dans la fenêtre principale, vous pouvez utiliser:

Dispatcher.BeginInvoke(...

Si vous êtes dans un autre contexte, par exemple un modèle de vue, utilisez:

Application.Current.Dispatcher.BeginInvoke(  

Invoke vs BeginInvoke
Utilisez Invoke si vous voulez que le thread actuel attende que le thread d'interface utilisateur ait traité le code de répartition ou BeginInvoke si vous voulez que le thread actuel continue sans attendre la fin de l'opération sur Fil d'interface utilisateur.

MessageBox, Dispatchers et Invoke/BeginInvoke:
Dispatcher.Invoke Bloquera votre fil jusqu'à ce que le MessageBox soit fermé.
Dispatcher.BeginInvoke Permettra à votre code de thread de continuer à s'exécuter tandis que le thread de l'interface utilisateur se bloquera sur l'appel MessageBox jusqu'à ce qu'il soit rejeté.

CurrentDispatcher vs Current.Dispatcher!
Méfiez-vous de Dispatcher.CurrentDispatcher Car je crois comprendre que cela renverra un répartiteur pour le thread actuel et non le thread de l'interface utilisateur. En général, vous êtes intéressé par le répartiteur sur le thread d'interface utilisateur - Application.Current.Dispatcher Renvoie toujours ceci.

Remarque supplémentaire:
Si vous constatez que vous devez souvent vérifier le répartiteur CheckAccess, une méthode d'aide utile est la suivante:

public void DispatchIfNecessary(Action action) {
    if (!Dispatcher.CheckAccess())
        Dispatcher.Invoke(action);
    else
        action.Invoke();
}

Qui peut être appelé comme:

DispatchIfNecessary(() => {
    network_links.Add(new NetworkLinkVM(link, start_node, end_node));
});
80
Ricibob

Quelque chose comme ça (du haut de ma tête) devrait fonctionner:

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

J'ai eu des problèmes avec Application.Current.Dispatcher.BeginInvoke Et les méthodes object.Invoke().

Cela a fonctionné pour moi:

Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
{
     // code...
}));
0
MNicoll