Je suis devenu douloureusement conscient de la fréquence à laquelle il faut écrire le modèle de code suivant dans le code GUI événementiel, où
private void DoGUISwitch() {
// cruisin for a bruisin' through exception city
object1.Visible = true;
object2.Visible = false;
}
devient:
private void DoGUISwitch() {
if (object1.InvokeRequired) {
object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
} else {
object1.Visible = true;
object2.Visible = false;
}
}
C'est un modèle gênant en C #, à la fois à retenir et à taper. Quelqu'un a-t-il trouvé une sorte de raccourci ou de construction qui automatise cela dans une certaine mesure? Ce serait cool s'il y avait un moyen d'attacher une fonction aux objets qui effectue cette vérification sans avoir à passer par tout ce travail supplémentaire, comme un object1.InvokeIfNecessary.visible = true
raccourci de type.
Les réponses précédentes ont discuté de l'impossibilité de simplement appeler Invoke () à chaque fois, et même dans ce cas, la syntaxe Invoke () est à la fois inefficace et toujours difficile à gérer.
Alors, est-ce que quelqu'un a trouvé des raccourcis?
la source
object1.InvokeIfNecessary.Visible = true
ligne; consultez ma réponse mise à jour et dites-moi ce que vous en pensez.Réponses:
L'approche de Lee peut être encore simplifiée
Et peut être appelé comme ça
Il n'est pas nécessaire de transmettre le contrôle en tant que paramètre au délégué. C # crée automatiquement un fermeture .
MISE À JOUR :
Selon plusieurs autres affiches
Control
peuvent être généralisées commeISynchronizeInvoke
:DonBoitnott a souligné que contrairement à
Control
l'ISynchronizeInvoke
interface, il faut un tableau d'objets pour laInvoke
méthode comme liste de paramètres pour leaction
.MISE À JOUR 2
Modifications suggérées par Mike de Klerk (voir le commentaire dans le 1er extrait de code pour le point d'insertion):
Voir le commentaire de ToolmakerSteve ci-dessous pour les préoccupations concernant cette suggestion.
la source
ISynchronizeInvoke
au lieu deControl
? (Félicitations à Jon Skeet stackoverflow.com/questions/711408/… )ISynchronizeInvoke
. Mais le seul type qui en dérive (selon Reflector) estControl
, donc l'avantage est limité.while (!control.Visible) ..sleep..
. Pour moi, cela a une mauvaise odeur de code, car il s'agit d'un délai potentiellement illimité (peut-être même une boucle infinie dans certains cas), dans un code qui peut avoir des appelants qui ne s'attendent pas à un tel retard (ou même à une impasse). À mon humble avis, toute utilisation deSleep
devrait être la responsabilité de chaque appelant, OU devrait être dans un emballage séparé clairement indiqué quant à ses conséquences. À mon humble avis, il serait généralement préférable de "échouer dur" (exception, pour attraper pendant les tests), ou de "ne rien faire" si le contrôle n'est pas prêt. Commentaires?InvokeRequired
indique si le thread appelant est différent du thread qui a créé le contrôle.Invoke
transmet l'action du thread appelant au thread du contrôle où elle est exécutée. Cela garantit que, par exemple, un gestionnaire d'événements Click n'est jamais interrompu.Vous pouvez écrire une méthode d'extension:
Et utilisez-le comme ceci:
EDIT: Comme Simpzon le souligne dans les commentaires, vous pouvez également changer la signature en:
la source
Voici le formulaire que j'ai utilisé dans tout mon code.
J'ai basé ceci sur l'entrée de blog ici . Je n'ai pas vu cette approche échouer, donc je ne vois aucune raison de compliquer mon code avec une vérification du
InvokeRequired
propriété.J'espère que cela t'aides.
la source
InvokeRequired
si le code peut être exécuté avant l'affichage du contrôle ou vous aurez une exception fatale.Créez un fichier ThreadSafeInvoke.snippet, puis vous pouvez simplement sélectionner les instructions de mise à jour, faire un clic droit et sélectionner `` Entourer de ... '' ou Ctrl-K + S:
la source
Voici une version améliorée / combinée des réponses de Lee, Oliver et Stephan.
Le modèle permet un code flexible et sans cast qui est beaucoup plus lisible tandis que le délégué dédié offre de l'efficacité.
la source
Je préfère utiliser une seule instance d'une méthode Delegate au lieu de créer une nouvelle instance à chaque fois. Dans mon cas, j'avais l'habitude d'afficher les messages de progression et (info / erreur) d'un Backroundworker copiant et diffusant des données volumineuses à partir d'une instance SQL. Chaque fois, après environ 70000 appels de progression et de messages, mon formulaire a cessé de fonctionner et d'afficher de nouveaux messages. Cela ne s'est pas produit lorsque j'ai commencé à utiliser un seul délégué d'instance globale.
la source
Usage:
Code:
la source
J'aime faire un peu différemment, j'aime m'appeler "moi-même" si nécessaire avec une action,
c'est un modèle pratique, le IsFormClosing est un champ que je définis sur True lorsque je ferme mon formulaire car il peut y avoir des threads d'arrière-plan qui sont toujours en cours d'exécution ...
la source
Vous ne devriez jamais écrire du code qui ressemble à ceci:
Si vous avez du code qui ressemble à ceci, votre application n'est pas thread-safe. Cela signifie que vous avez du code qui appelle déjà DoGUISwitch () à partir d'un autre thread. Il est trop tard pour vérifier s'il s'agit d'un autre thread. InvokeRequire doit être appelé AVANT d'appeler DoGUISwitch. Vous ne devez accéder à aucune méthode ou propriété à partir d'un thread différent.
Référence: Control.InvokeRequired Propriété où vous pouvez lire ce qui suit:
Dans une architecture à processeur unique, il n'y a pas de problème, mais dans une architecture à plusieurs processeurs, vous pouvez affecter une partie du thread de l'interface utilisateur au processeur sur lequel le code appelant s'exécutait ... et si ce processeur est différent de celui où le thread de l'interface utilisateur était alors en cours d'exécution lorsque le thread appelant se termine, Windows pensera que le thread d'interface utilisateur est terminé et tuera le processus d'application, c'est-à-dire que votre application se fermera sans erreur.
la source
invoke()
et autres avant que le contrôle ne reçoive une poignée, mais IMHO ne décrit pas ce que vous avez décrit. Le but de toutes cesinvoke()
absurdités est de mettre à jour l'interface utilisateur d'une manière thread-safe, et je pense que mettre plus d' instructions dans un contexte de blocage conduirait à un bégaiement? (Ugh ... content d'avoir arrêté d'utiliser la technologie M $. Tellement compliqué!)