Question

Pour jouer un peu avec le threading, les délégués et les arrière-plans, je construis quelques petites applications et j'ai quelques problèmes avec l'une d'entre elles. J'ai un formulaire Windows, avec une zone de texte, un bouton et un richttext. Lorsque j'appuie sur le bouton, le texte dans la zone de texte est utilisé comme paramètre pour instancier une classe, comme ceci:

public partial class Form1 : Form
{
    private BackgroundWorker backgroundWorker;

    public Form1()
    {
        InitializeComponent();            
    }

    private void button1_Click(object sender, EventArgs e)
    {   
        backgroundWorker = new BackgroundWorker();
        backgroundWorker.DoWork += new DoWorkEventHandler(worker_DoWork);
        backgroundWorker.RunWorkerAsync();
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        new Thread((ThreadStart)delegate()
        {
            this.BeginInvoke((ThreadStart)delegate()
            {
                foreach (string line in textBox1.Lines)
                {  
                    Dig digger = new Dig(line, textBox1.Text);
                    digger.DomainChecked += new Dig.DomainCheckedHandler(OnUpdateTicker);

                    string response = digger.GetAllInfo();

                    richTextBox1.AppendText(response);
                    Application.DoEvents();
                }
            });
        }).Start();
    }

    void OnUpdateTicker(string msg)
    {
        new Thread((ThreadStart)delegate()
        {
            this.BeginInvoke((ThreadStart)delegate()
            {
                label4.Text = msg;
                Application.DoEvents();
            });
        }).Start();            
    }
}

Lors du débogage, je me suis heurté à un 'textBox1.Lines' qui a renvoyé une exception de type 'Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException' Des astuces pour résoudre ce problème?

Était-ce utile?

La solution

Premièrement, il n'est pas nécessaire de créer de nouveaux threads dans DoWork ; L'idée avec BackgroundWorker est que DoWork est exécuté sur un thread séparé. Deuxièmement, comme DoWork est exécuté sur un thread séparé et que les contrôles de l'interface utilisateur ne peuvent être modifiés que sur le thread de l'interface utilisateur, vous devez appeler ces mises à jour correctement. Ainsi, une version réécrite de worker_DoWork pourrait ressembler à ceci:

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    foreach (string line in textBox1.Lines)
    {  
        Dig digger = new Dig(line, textBox1.Text);
        digger.DomainChecked += new Dig.DomainCheckedHandler(OnUpdateTicker);
        string response = digger.GetAllInfo();
        richTextBox1.Invoke((Action) delegate { richTextBox1.AppendText(response); });
    }
}

Notez que le code ne génère pas explicitement de nouveaux threads et que l'appel de la méthode AppendText est effectué via un appel Control.Invoke , l'obligeant à s'exécuter le fil de l'interface utilisateur.

Autres conseils

La raison principale est que la zone de texte n'appartient pas au thread d'arrière-plan.

Votre fil d'interface utilisateur possède tous les objets d'interface utilisateur et vous créez un fil d'arrière-plan lorsqu'un bouton est enfoncé. Ce fil d’arrière-plan ne devrait avoir accès à aucun objet d’UI.

Si vous souhaitez que la valeur de la zone de texte soit utilisée, vous devez la transmettre à votre thread d'arrière-plan d'une autre manière.

Regardez Cliquez ici pour une explication (et une solution).

Vous pouvez uniquement mettre à jour les contrôles sur le thread principal à partir du thread principal lui-même, à moins d'indiquer explicitement que votre programme le permet, en utilisant la méthode .Invoke du contrôle.

From: http://www.albahari.com/threading/part3.aspx

Control.Invoke

Dans une application Windows Forms multi-thread, il est interdit d'appeler une méthode ou une propriété sur un contrôle à partir d'un thread autre que celui qui l'a créé. Tous les appels inter-thread doivent être explicitement assignés au thread qui a créé le contrôle (généralement le thread principal), à l'aide de la méthode Control.Invoke ou Control.BeginInvoke. On ne peut pas compter sur le tri automatique, car il intervient trop tard - cela ne doit se faire que lorsque l'exécution pénètre bien dans du code non managé, période à partir de laquelle de nombreux codes internes .NET peuvent déjà avoir été exécutés de manière "erronée". thread - code qui n'est pas thread-safe.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top