100 votes

Invoke(Délégué)

Quelqu'un peut-il expliquer cette déclaration écrite sur ce enlace

Invoke(Delegate):

Exécute le délégué spécifié sur le thread qui possède l'objet la poignée de fenêtre sous-jacente du contrôle.

Quelqu'un peut-il m'expliquer ce que cela signifie (en particulier le texte en gras) ? Je ne comprends pas bien.

137voto

dash Points 22583

La réponse à cette question réside dans le fonctionnement des contrôles C#.

Les contrôles dans Windows Forms sont liés à un thread spécifique et ne sont pas thread safe. Par conséquent, si vous appelez la méthode d'un contrôle à partir d'une d'un autre thread, vous devez utiliser l'une des méthodes invoke du contrôle pour pour transférer l'appel vers le bon thread. Cette propriété peut être utilisée pour déterminer si vous devez appeler une méthode d'invocation, ce qui peut être utile si vous ne savez pas à quel thread appartient un contrôle.

En Contrôle.InvokeRequired

En fait, Invoke permet de s'assurer que le code que vous appelez est exécuté sur le fil d'exécution sur lequel le contrôle "vit", ce qui permet d'éviter les exceptions intersectorielles.

D'un point de vue historique, en .Net 1.1, cela était autorisé. Cela signifie que vous pouviez essayer d'exécuter du code sur le thread "GUI" à partir de n'importe quel thread d'arrière-plan et que cela fonctionnait la plupart du temps. Parfois, cela provoquait simplement la sortie de votre application parce que vous interrompiez effectivement le thread de l'interface graphique pendant qu'il faisait autre chose. C'est le Exception croisée - Imaginez que vous essayez de mettre à jour un TextBox pendant que l'interface graphique peint autre chose.

  • Quelle action est prioritaire ?
  • Est-il possible que les deux se produisent en même temps ?
  • Qu'advient-il de toutes les autres commandes que l'interface graphique doit exécuter ?

En fait, vous interrompez une file d'attente, ce qui peut avoir de nombreuses conséquences imprévues. Invoke est effectivement la manière "polie" d'introduire ce que vous voulez faire dans cette file d'attente, et cette règle a été appliquée à partir de .Net 2.0 par le biais d'une fonction lancée InvalidOperationException .

Pour comprendre ce qui se passe réellement en coulisses, et ce que l'on entend par "thread GUI", il est utile de comprendre ce qu'est une pompe à messages ou une boucle à messages.

En fait, la réponse à cette question se trouve déjà dans la question " Qu'est-ce qu'une pompe à message ? "Il s'agit d'une lecture recommandée pour comprendre le mécanisme réel dans lequel vous vous engagez lorsque vous interagissez avec les commandes.

D'autres lectures peuvent vous être utiles :

Qu'est-ce qui se passe avec Begin Invoke

L'une des règles cardinales de la programmation d'une interface graphique Windows est que seul le fil d'exécution qui a créé l'interface graphique peut être utilisé. le thread qui a créé un contrôle peut accéder à son contenu et/ou le modifier (sauf pour quelques exceptions documentées). Essayez de le faire à partir de n'importe quel autre thread et vous obtiendrez un comportement imprévisible allant du blocage à des exceptions et une interface utilisateur à moitié mise à jour. La bonne façon de mettre à jour un contrôle à partir d'un autre thread est de poster un message approprié dans la queue de file d'attente des messages de l'application. Lorsque la pompe à messages se charge d'exécuter ce message l'exécution de ce message, le contrôle sera mis à jour, dans le même qui l'a créé (rappelez-vous que la pompe à messages s'exécute sur le thread principal). principal).

et, pour un aperçu plus lourd en code avec un échantillon représentatif :

Opérations inter-filières invalides

// the canonical form (C# consumer)

public delegate void ControlStringConsumer(Control control, string text);  // defines a delegate type

public void SetText(Control control, string text) {
    if (control.InvokeRequired) {
        control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text});  // invoking itself
    } else {
        control.Text=text;      // the "functional part", executing only on the main thread
    }
}

Une fois que vous aurez compris le fonctionnement de InvokeRequired, vous pourrez envisager d'utiliser une méthode d'extension pour envelopper ces appels. La question Stack Overflow aborde ce sujet de manière très pertinente. Nettoyage du code truffé d'invocations obligatoires .

Il existe également un autre un compte-rendu de ce qui s'est passé historiquement qui pourraient vous intéresser.

74voto

Thomas Levesque Points 141081

Un contrôle ou un objet fenêtre dans Windows Forms n'est qu'une enveloppe autour d'une fenêtre Win32 identifiée par un identifiant poignée (parfois appelé HWND). La plupart des choses que vous faites avec le contrôle se traduiront éventuellement par un appel à l'API Win32 qui utilise ce handle. Le handle appartient au thread qui l'a créé (généralement le thread principal) et ne doit pas être manipulé par un autre thread. Si, pour une raison quelconque, vous devez faire quelque chose avec le contrôle à partir d'un autre thread, vous pouvez utiliser la commande Invoke pour demander au fil principal de le faire en votre nom.

Par exemple, si vous souhaitez modifier le texte d'une étiquette à partir d'un fil de travail, vous pouvez procéder comme suit :

theLabel.Invoke(new Action(() => theLabel.Text = "hello world from worker thread!"));

28voto

Mehmet Ataş Points 3560

Si vous voulez modifier un contrôle, vous devez le faire dans le fil de discussion dans lequel le contrôle a été créé. Voici Invoke vous permet d'exécuter des méthodes dans le thread associé (le thread qui possède le gestionnaire de fenêtre sous-jacent du contrôle).

Dans l'exemple ci-dessous, le thread1 lève une exception parce que SetText1 essaie de modifier textBox1.Text depuis un autre thread. Mais dans le thread2, l'action de SetText2 est exécutée dans le thread dans lequel la TextBox a été créée.

private void btn_Click(object sender, EvenetArgs e)
{
    var thread1 = new Thread(SetText1);
    var thread2 = new Thread(SetText2);
    thread1.Start();
    thread2.Start();
}

private void SetText1() 
{
    textBox1.Text = "Test";
}

private void SetText2() 
{
    textBox1.Invoke(new Action(() => textBox1.Text = "Test"));
}

8voto

BestDeveloper Points 67
Invoke((MethodInvoker)delegate{ textBox1.Text = "Test"; });

3voto

Srikanth Points 321

this.Invoke(delegate) assurez-vous que vous appelez le délégué que l'argument à this.Invoke() sur le fil principal/le fil créé.

Je peux dire une règle du pouce : n'accédez pas aux contrôles de votre formulaire sauf depuis le fil principal.

Les lignes suivantes peuvent être utiles pour utiliser Invoke()

    private void SetText(string text)
    {
        // InvokeRequired required compares the thread ID of the
        // calling thread to the thread ID of the creating thread.
        // If these threads are different, it returns true.
        if (this.textBox1.InvokeRequired)
        {   
            SetTextCallback d = new SetTextCallback(SetText);
            this.Invoke(d, new object[] { text });
        }
        else
        {
            this.textBox1.Text = text;
        }
    }

Dans certaines situations, si vous créez un thread Threadpool (c'est-à-dire un thread de travail), il sera exécuté sur le thread principal. Il ne créera pas de nouveau thread car le thread principal est disponible pour traiter d'autres instructions. Donc, il faut d'abord vérifier si le thread en cours d'exécution est le thread principal à l'aide de la commande this.InvokeRequired Si le résultat est vrai, le code actuel s'exécute sur le fil d'exécution du travailleur. this.Invoke(d, new object[] { text }) ;

Sinon, mettez directement à jour le contrôle de l'interface utilisateur (ici, vous avez la garantie que vous exécutez le code sur le fil principal).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X