.NET BackGroundWorker - InvalidOperationException : inter-threads non valide
J'ai un projet codé en .NET Winforms.
J'ai besoin de mettre en œuvre une opération d'exploitation de données, imprimer le texte de la TextBox et mise à jour de la progression.
J'ai essayé d'utiliser BackgroundWorker à faire, mais il déclenche une exception InvalidOperationException (inter-threads non valide: le Contrôle "xxxxx" accessible à partir d'un thread autre que le thread qu'il a été créé sur)
Pour affiner les causes possibles du problème, j'ai commencé un nouveau projet, notamment les suivantes:
Bouton Pour démarrer le composant BackgroundWorker
Étiquette pour imprimer le texte.
Et ProgressBar.
Cependant, le résultat est le même. J'ai cherché sur SOF, et m'a dit d'utiliser un délégué, mais je ne suis pas familier avec elle.
C'est l'exemple de code qui génère l'erreur:
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace TestProject
{
public partial class Form1 : Form
{
private readonly BackgroundWorker _bw = new BackgroundWorker();
public Form1()
{
InitializeComponent();
_bw.DoWork += RosterWork;
_bw.ProgressChanged += BwProgressChanged;
_bw.RunWorkerCompleted += BwRunWorkerCompleted;
_bw.WorkerReportsProgress = true;
_bw.WorkerSupportsCancellation = false;
}
private void RosterWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
for (int i = 0; i < 1000; i++)
{
label1.Text = i.ToString();
_bw.ReportProgress(Convert.ToInt32((i * (100 / 1000))));
}
}
private void BwProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void btnStart_Click(object sender, EventArgs e)
{
progressBar1.Show();
_bw.RunWorkerAsync();
}
private void BwRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressBar1.Hide();
}
}
}
Mise à jour:
J'ai suivi Jon Skeet réponse, - il vraiment travailler sur mon projet de test, mais pour en revenir à mon projet,
La Mise en page de mon Formulaire:
Forme -
TabControl
- Tab1
-Tab1Panel
-TextBox1
Quand atteignent cette ligne :
TextBox txtbox1 = new TextBox();
Tab1Panel.Controls.Add(txtbox1);
L'erreur se produisent encore quand j'ajoute de la zone de texte du Panneau de Contrôle par programmation.
Enfin,je l'ai remplacer par ceci:
if (Tab1Panel.InvokeRequired)
Tab1Panel.Invoke((MethodInvoker)delegate { Tab1Panel.Controls.Add(txtbox1); });
else
Tab1Panel.Controls.Add(txtbox1);
Tout ce qui est travail. Comment faire pour déterminer le contrôle est InvokeRequired, Est-il un contrôle d'?
OriginalL'auteur Cheung | 2011-11-01
Vous devez vous connecter pour publier un commentaire.
C'est le problème:
Vous essayez de modifier le texte de l'étiquette à l'intérieur de la
BackgroundWorker
, ce qui n'est pas en cours d'exécution sur un thread d'INTERFACE utilisateur. Le point deBackgroundWorker
est à faire tous les non-INTERFACE de travail, en utilisantReportProgress
périodiquement "retour en arrière" pour le thread d'INTERFACE utilisateur et de mise à jour de l'INTERFACE utilisateur avec les progrès que vous faites.Donc soit vous avez besoin de changer
label1.Text
dansBwProgressChanged
ainsi, ou vous devez utiliserControl.Invoke
/BeginInvoke
comme vous le feriez de toute autre thread d'arrière-plan:Pour en savoir plus sur la copie de la partie, voir Eric Lippert du blog, "La fermeture de plus de la variable de boucle considéré comme nocif". Dans ce cas particulier, il est seulement une question parce que je suis en utilisant
BeginInvoke
. Cette pourrait être modifié pour seulement:... mais maintenant, le fond travailleur serait toujours en attente pour l'INTERFACE utilisateur pour le rattraper avant qu'il continuait à avancer, qui dans la vraie vie est généralement pas ce que vous voulez. Je préfère généralement
BeginInvoke
surInvoke
.Voulez-vous dire "qui est pas en cours d'exécution sur un thread d'INTERFACE utilisateur"?
Yup, merci fixe.
Je crains que je ne comprends pas vraiment votre commentaire particulièrement "chacun d'entre eux est plus comme des normes"...
OriginalL'auteur Jon Skeet
utiliser ce code iw va travailler
OriginalL'auteur vzades
Vous êtes accédant à votre étiquette qui a été créé sur le thread GUI - de l'intérieur de votre backgroundworker-fil.
L'accès à un contrôle de Windows à partir d'un thread autre que sur laquelle le contrôle a été créé, n'est pas autorisé; par conséquent, vous avez donné l'exception.
Vous ne devriez pas accéder à l'étiquette directement, mais vous devez soulever un événement au sein de votre fil, et assurez-vous qu'il est invoqué sur le thread approprié - que les signaux de l'INTERFACE utilisateur, de sorte que vous pouvez modifier le contenu de l'étiquette.
OriginalL'auteur Frederik Gheysels
Vous devez exécuter les méthodes de contrôle de la thread qui les a créés. Pour les mettre à jour à partir d'un autre thread utiliser Invoquer. Un exemple de la façon dont cela peut être fait peut être trouvé ici. Vous devriez également lire Le Multithreading avec des Formulaires et des Contrôles sur MSDN.
OriginalL'auteur Sascha Hennig