2011-05-30 3 views
5

Je suis en train de modifier une application écrite en C# qui fait un usage intensif du multi-threading pour lire des fichiers audio et afficher des images à un utilisateur. Étant donné qu'il est multi-thread, j'ai besoin d'utiliser la méthode Invoke souvent pour modifier les éléments de formulaire. Je suis en train de tomber sur un schéma avec lequel je ne suis pas très à l'aise, où je me retrouve à écrire de petites méthodes de délégation fréquentes qui ne font qu'une chose. Un exemple de ceci est comme suit:Qu'est-ce qui est considéré comme une bonne pratique de programmation dans les applications winform multithread avec utilisation déléguée?

delegate void setImageCallback(Image img); 
private void setImage(Image img) 
{ 
    this.pictureBox1.Image = img; 
} 

private void someOtherMethod() 
{ 
    ... 
    if (this.pictureBox1.InvokeRequired) 
    { 
     this.Invoke(new setImageCallback(setImage), Image.FromFile("example.png"); 
    } 
    else 
    { 
     this.pictureBox1.Image = Image.FromFile("example.png"); 
    } 
    ... 
} 

Comment les gens gèrent généralement ces situations, de sorte que vous ne trouvez pas vous écrire un nombre absurde de délégués et méthodes juste pour rester thread-safe? Évidemment, la consolidation de méthodes similaires est géniale, mais si je dois potentiellement mettre à jour chaque élément de formulaire sur mon formulaire, je ne souhaite pas avoir de délégué et de méthode "modify" pour chacun de ces éléments.

Merci.

+0

http://stackoverflow.com/questions/2367718/c-automating-the-invokerequired-code- pattern/2367888 # 2367888 –

Répondre

6

Vous n'avez certainement pas besoin d'un délégué distinct pour chacun. Vous pouvez utiliser Action délégués et des expressions lambda pour simplifier, comme ceci:

private void SomeOtherMethod() 
{ 
    Action action =() => pictureBox1.Image = Image.FromFile("example.png"); 
    if (pictureBox1.InvokeRequired) 
    { 
     Invoke(action); 
    } 
    else 
    { 
     action(); 
    } 
} 

Ou vous pouvez séparer la déclaration if et InvokeRequired vérification et de généraliser encore plus, comme ceci:

public static void InvokeIfRequired(Control control, Action action) 
{ 
    if (control.InvokeRequired) 
    { 
     control.Invoke(action); 
    } 
    else 
    { 
     action(); 
    } 
} 

private void SomeOtherMethod() 
{ 
    InvokeIfRequired(() => pictureBox1.Image = Image.FromFile("example.png"); 
} 
+0

C'est intéressant ... est-ce typiquement ce qui est fait en "entreprise"? Aussi, par curiosité ... que se passerait-il si vous utilisiez Invoke alors que ce n'était pas nécessaire? Souhaitez-vous simplement faire des appels de méthode inutiles et augmenter les frais généraux, ou cela viole-t-il la sécurité des threads? – rybosome

+0

J'avais l'habitude d'avoir une méthode exactement comme ceci dans ma bibliothèque de misc (même nom aussi), mais je l'ai eu comme méthode d'extension. Entré en pratique. Bien que je préfère la façon dont je l'ai fait ci-dessous ces jours-ci. Encore, +1. –

+0

@Ryan, lorsque vous appelez 'Invoke', le délégué est placé dans la file d'attente des messages des contrôles, puis l'appelant attend qu'il soit exécuté. Vous pouvez faire la même chose sans attendre en appelant 'BeginInvoke', ce qui est probablement mieux dans la plupart des cas. Appeler 'Invoke' inutilement peut retarder les actions car elles sont ajoutées à la file d'attente des messages au lieu d'être traitées immédiatement. Ce n'est probablement pas perceptible, mais encore frais généraux inutiles. –

8

Un bon exemple est here.

this.BeginInvoke((Action) (()=> 
    { 
     pictureBox1.Image = Image.FromFile("example.png"); 
    })); 
+0

Instructions pour faire une recherche ne fait pas vraiment une bonne réponse. Si vous venez de modifier et supprimer la partie "faire une recherche google", ce serait mieux. –

+0

Ok enlevé ... J'allais taper un exemple, mais je suis en train de faire cuire quelque chose ... ce fut le meilleur que je pouvais faire rapidement sans brûler ma nourriture;) –

+0

ne veut certainement pas que vous brûliez ta nourriture. :-) Merci pour la mise à jour, votre réponse est beaucoup mieux maintenant. –

1

I utiliserait le type MethodInvoker en conjonction avec une méthode anonyme ou une expression lambda. Je voudrais aussi construire la logique d'invocation dans la méthode elle-même, plutôt que d'utiliser une méthode de thread-safe séparé:

void SomeMethod(/* with whatever args */) { 
    if (InvokeRequired) 
     Invoke(new MethodInvoker(() => SomeMethod(/* args used to call method */))); 
    else 
     // the method body itself 
} 
Questions connexes