2010-10-31 7 views
2

J'ai créé le projet suivant pour vous montrer comment je prévois faire les choses. Mais mon projet principal sera plus grand et aura plusieurs classes. J'essaie simplement de faire en sorte que cela fonctionne correctement, alors je sais que j'utilise les bonnes pratiques pour coder. Ok, permet de commencer :), donc mon formulaire a un bouton appelé "button1" et une zone de texte appelée "textBox1" et j'ai une classe appelée "Class1" qui a une méthode "testtest()", je viens de Mettez Thread.Sleep dans la méthode testtest afin que je puisse trouver son fonctionnement sur un autre thread.C# Multithread application multiclux gui, est-ce que je fais ce droit?

Voici mon code sous forme

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace Test 
{ 
    public partial class Form1 : Form 
    { 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    delegate void Class1Deligate(); 

    private void button1_Click(object sender, EventArgs e) 
    { 
     Class1 c = new Class1(); 
     Class1Deligate testMethod = new Class1Deligate(c.testtest); 
     testMethod.BeginInvoke(endTestMethod, testMethod); 
    } 

    void endTestMethod(IAsyncResult ar) 
    { 

    } 
    } 
} 

et voici ma classe d'un code

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Windows.Forms; 

namespace Test 
{ 
    class Class1 
    { 
    public void testtest() 
    { 
     Thread.Sleep(8888); 
     MessageBox.Show("Done"); 
    } 
    } 
} 

Suis-je créer correctement un nouveau thread? Et quelqu'un peut me dire s'il vous plaît comment mettre à jour textbox1 de la méthode testtest dans class1 pendant son fonctionnement? J'ai fait un post plus tôt et on m'a dit d'utiliser Dispatcher, mais pour une raison quelconque, il semble que la classe Dispatcher ne soit pas disponible pour moi.

Cordialement

Répondre

1

Je ne pense pas que vous commencez réellement un nouveau thread. delegate.BeginInvoke utilise probablement le ThreadPool interne pour faire les enchères. Et en note, je ne pense pas que vous devriez appeler BeginInvoke sans l'appel approprié EndInvoke après (sinon la référence à l'IAsyncResult retourné de l'appel BeginInvoke ne sera pas publié).

Si vous voulez un nouveau sujet, vous pouvez en créer un nouveau en utilisant la classe Thread.

Thread t = new Thread(c.testtest); 
t.IsBackground = true; // end if main thread ends 
t.Start(); 

Notez que si vous utilisez la classe Thread comme ci-dessus, et en utilisant l'interface graphique, vous devez joindre une méthode au fil de l'interface graphique pour le mettre à jour. Vous pouvez le faire en utilisant l'appel Control.Invoke

public void updateGUI(object state) { 
    if (control.InvokeRequired) { 
     control.Invoke(new Action<object>(updateGUI), state); 
     return; 
    } 
    // if we are here, we can safely update the GUI 
} 
+0

Je ne suis pas sûr si je veux un nouveau fil ou pas, parce que dans certains exemples, je vois la classe Thread est utilisée et dans d'autres, je vois que BeginInvoke est utilisé, donc c'est vraiment confus. – Arya

+0

@Arya: Eh bien, certains commencent un nouveau thread, certains utilisent l'arrière-plan, certains utilisent le ThreadPool. C'est à vous de déterminer ce qui convient le mieux au moment où vous l'utilisez. Toutes les méthodes ont leurs avantages et leurs inconvénients. – Patrick

0

Tout d'abord, il y a la classe ThreadPool disponible pour enfiler si vous le souhaitez. C'est ce que j'utilise généralement pour déclencher de nouveaux threads, par exemple,

ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i); 

Le lien explique un peu plus à leur sujet. Comme pour l'interface graphique, vous devrez faire une vérification pour voir si le thread actuel est le même thread que le thread UI (comme seul le thread UI peut mettre à jour l'interface utilisateur), et si ce n'est pas, invoquer une fonction sur le Fil d'interface utilisateur. Cela peut être fait comme si,

delegate void ChangeFormUnsafeCallback(string text); 
private void ChangeFormUnsafe(string text) 
{ 
    // Do stuff to form/controls 
} 

private void SomeFunction() 
{  
    myForm.Invoke(new ChangeFormUnsafeCallback(ChangeFormUnsafe), "foo"); 
} 

Vous pouvez faire une vérification pour voir si l'Invoke est nécessaire, mais il est généralement assez simple de savoir si la fonction sera utilisée dans le thread d'interface utilisateur ou non et Invoke appropriée . En règle générale, à moins que votre fonction ne soit exécutée suite à un événement survenu sur le formulaire (par exemple, un clic sur le bouton), vous devrez utiliser la fonction Appeler.

+0

Vous savez si vous devez ou non utiliser Invoke en cochant 'InvokeRequired' ... Et vous n'avez pas * besoin * de déclarer un nouveau délégué, vous pouvez utiliser' Action '. – Patrick

+0

@Patrick Oui, je sais que vous pouvez vérifier avec InvokeRequired, je disais juste que 99% du temps, vous aurez besoin d'une invocation, car seuls les événements déclenchés par l'interface utilisateur s'exécuteront sur le thread de l'interface utilisateur. – mike

0

Arya

Utilisation de votre approche (async délégués), vous n'êtes pas un nouveau thread commencer, mais vous utilisez un fil de la .net threadpool, qui sera libérée lorsque votre travail est fait.La bonne façon d'invoquer le délégué et être calledback lorsque vous avez terminé est la suivante:

void button1_Click(object sender, EventArgs e) 
    { 
     Class1 c = new Class1(); 
     Action action = c.Test; 

     action.BeginInvoke(new AsyncCallback(EndTestMethod), null); 
    } 
    void EndTestMethod(IAsyncResult token) 
    {  
     Action callBack = (Action)((AsyncResult)token).AsyncDelegate; 
     callBack.EndInvoke(token); 
    } 

L'approche délégué asynchrone est utile si votre méthode est assez courte durée et vous avez besoin d'un rappel. Sinon, pour un processus plus long, vous pouvez créer et démarrer un nouveau thread.

Thread t = new Thread(c.Test); 
     t.IsBackground = true; 
     t.Start(); 

Cependant, la signalisation au thread d'appel, par un rappel, deviendra de plus longue haleine que vous devrez écrire ce code vous-même. En ce qui concerne Dispatcher, il s'agit d'une classe WPF qui met en file d'attente les actions à gérer par le thread UI dans les applications WPF (entre autres). À partir de votre code, il semble que vous écrivez une application Winforms, ce type n'est donc pas approprié.

Enfin, pour mettre à jour la zone de texte, vous devez vérifier si vous essayez d'accéder à ce contrôle sur le même thread qui a créé le contrôle (thread UI). Ceci est fait via control.invokerequired et control.invoke. Comme suit:

 void AddText(string text) 
    { 
     if (textBox1.InvokeRequired) 
     { 
      textBox1.Invoke((Action<string>)AddText, text); 
     } 
     textBox1.Text = text; 
    } 
0

Selon ce que vous essayez d'accomplir, il y a quelques different façons dont vous pouvez aller. Si vous souhaitez exécuter une seule tâche sans bloquer votre thread d'interface utilisateur, vous pouvez utiliser le BackgroundWorker. Cela vous donnera un moyen très simple de garder votre interface utilisateur conviviale et facilitera la mise à jour de l'interface utilisateur sans avoir recours à Invoke, etc.

Si vous vous lancez dans de nombreuses tâches, vous devriez probablement utiliser le ThreadPool. Si vous devez attribuer une priorité aux threads ou qu'ils passent beaucoup de temps à bloquer, vous devez créer vos propres threads d'instance.

Vous pouvez bien sûr continuer à faire des choses comme vous, qui utiliseront le ThreadPool, mais il existe d'autres approches qui pourraient mieux répondre à vos besoins particuliers.

Questions connexes