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.