L'article de MSDN : Comment faire : Effectuer des appels sécurisés pour les contrôles Windows Forms dit que nous devrions utiliser un délégué asynchrone pour faire l'appel. Mais pourquoi le délégué asynchrone rend-il l'appel sûr ?
Réponses
Trop de publicités?Les contrôles Windows utilisent le modèle d'appartement unique (STA) du Component Object Model (COM) parce que ces contrôles sous-jacents sont des appartements-threads. En outre, de nombreux contrôles utilisent la pompe à messages pour de nombreuses opérations. Ce modèle stipule que tous les appels de fonction à chaque contrôle doivent se faire sur le même thread qui a créé le contrôle. Invoke (et BeginInvoke et EndInvoke) achemine les appels de méthode vers le bon thread.
Extrait de More Effective C# de Bill Wagner. Point 16. Comprendre les appels inter-filières dans Windows Forms et WPF
Vous appellerez control.BeginInvoke() ou control.Invoke() et cette méthode se chargera d'insérer votre délégué dans le thread de distribution de l'interface graphique en toute sécurité, de sorte que, un peu plus tard, votre délégué sera traité et exécuté dans le thread de l'interface graphique et non dans le thread dans lequel vous vous trouvez.
L'essentiel est là : Vous ne devriez pas mettre à jour les contrôles de l'interface utilisateur à partir d'un thread autre que celui sur lequel le contrôle a été créé (UI / Main Thread). Sinon, vous risquez d'observer des comportements imprévisibles.
Si vous devez mettre à jour l'interface utilisateur à partir d'un fil de travail (autre que le fil principal), vous devez revenir au fil d'interface utilisateur avant de mettre à jour l'interface utilisateur.
L'article suggère d'utiliser
-
IsInvokeRequired
(qui renvoie vrai si le thread actuel n'est pas celui dans lequel l'interface utilisateur a été créée) etInvoke(delegate)
qui exécute le délégué sur le thread correct/UI. Ceci est utile lorsque vous voulez mettre à jour l'interface utilisateur. entre les deux le processus asynchrone. Par exemple, mettre à jour la progression sur l'interface utilisateur. -
BackgroundWorker
qui exécute les gestionnaires enregistrés pour sonDoWork
asynchrone sur un fil de travail et exécute les gestionnaires enregistrés pour son événement.RunWorkerCompleted
sur le thread appelant. C'est l'idéal si vous voulez mettre à jour l'interface utilisateur avec quelque chose après la tâche asynchrone est terminée, par exemple en affichant une indication "Done" sur l'interface utilisateur.
En effet, les contrôles des formulaires Windows sont conçus de cette manière, de sorte qu'on ne peut y accéder qu'à l'intérieur du fil de discussion qui leur appartient. Et le délégué asynchrone, lorsqu'il est utilisé correctement, rend l'appel sûr.
La réponse à la question posée est contenue dans le deuxième paragraphe de l'article MSDN donné =)
L'accès aux contrôles Windows Forms n'est pas intrinsèquement sûr pour les threads. Si deux threads ou plus manipulent l'état d'un contrôle, il est possible de forcer le contrôle dans un état incohérent. D'autres bogues liés aux threads sont possibles, tels que des conditions de course et des blocages. Il est important de s'assurer que l'accès à vos contrôles est effectué de manière sûre pour les threads.
Vous devez vérifier si vous pouvez accéder au contrôle immédiatement, sans indirection (en vérifiant la propriété InvokeRequired), si vous ne pouvez pas, vous devez y accéder de manière asynchrone (explication très simplifiée : le système attendra jusqu'à ce qu'il puisse accéder à un contrôle en toute sécurité).