Comment mettre à jour l’interface graphique d’un autre thread?

Quelle est la manière la plus simple de mettre à jour une Label depuis un autre thread?

J’ai un Form sur le thread1 et à partir de là, je commence un autre thread ( thread2 ). Pendant que thread2 traite certains fichiers, j’aimerais mettre à jour une Label sur le Form avec le statut actuel du travail de thread2 .

Comment puis je faire ça?

Pour .NET 2.0, voici un joli code que j’ai écrit et qui correspond exactement à ce que vous voulez, et fonctionne pour toutes les propriétés d’un Control :

 private delegate void SetControlPropertyThreadSafeDelegate( Control control, ssortingng propertyName, object propertyValue); public static void SetControlPropertyThreadSafe( Control control, ssortingng propertyName, object propertyValue) { if (control.InvokeRequired) { control.Invoke(new SetControlPropertyThreadSafeDelegate (SetControlPropertyThreadSafe), new object[] { control, propertyName, propertyValue }); } else { control.GetType().InvokeMember( propertyName, BindingFlags.SetProperty, null, control, new object[] { propertyValue }); } } 

Appelez-le comme ceci:

 // thread-safe equivalent of // myLabel.Text = status; SetControlPropertyThreadSafe(myLabel, "Text", status); 

Si vous utilisez .NET 3.0 ou une version ultérieure, vous pouvez réécrire la méthode ci-dessus en tant que méthode d’extension de la classe Control , ce qui simplifierait alors l’appel à:

 myLabel.SetPropertyThreadSafe("Text", status); 

MISE À JOUR 05/10/2010:

Pour .NET 3.0, vous devez utiliser ce code:

 private delegate void SetPropertyThreadSafeDelegate( Control @this, Expression> property, TResult value); public static void SetPropertyThreadSafe( this Control @this, Expression> property, TResult value) { var propertyInfo = (property.Body as MemberExpression).Member as PropertyInfo; if (propertyInfo == null || !@this.GetType().IsSubclassOf(propertyInfo.ReflectedType) || @this.GetType().GetProperty( propertyInfo.Name, propertyInfo.PropertyType) == null) { throw new ArgumentException("The lambda expression 'property' must reference a valid property on this Control."); } if (@this.InvokeRequired) { @this.Invoke(new SetPropertyThreadSafeDelegate (SetPropertyThreadSafe), new object[] { @this, property, value }); } else { @this.GetType().InvokeMember( propertyInfo.Name, BindingFlags.SetProperty, null, @this, new object[] { value }); } } 

qui utilise des expressions LINQ et lambda pour permettre une syntaxe beaucoup plus propre, plus simple et plus sûre:

 myLabel.SetPropertyThreadSafe(() => myLabel.Text, status); // status has to be a ssortingng or this will fail to comstack 

Non seulement le nom de la propriété est-il vérifié au moment de la compilation, mais le type de la propriété l’est également. Il est donc impossible (par exemple) d’affecter une valeur de chaîne à une propriété booléenne et de provoquer une exception d’exécution.

Malheureusement, cela n’empêche personne de faire des choses stupides telles que la transmission de la propriété et de la valeur d’un autre Control .

 myLabel.SetPropertyThreadSafe(() => aForm.ShowIcon, false); 

J’ai donc ajouté les vérifications à l’exécution pour m’assurer que la propriété transmise appartient bien au Control lequel la méthode est appelée. Pas parfait, mais toujours bien meilleur que la version .NET 2.0.

Si quelqu’un a d’autres suggestions sur la façon d’améliorer ce code pour la sécurité au moment de la compilation, veuillez commenter!

La méthode la plus simple est une méthode anonyme transmise à Label.Invoke :

 // Running on the worker thread ssortingng newText = "abc"; form.Label.Invoke((MethodInvoker)delegate { // Running on the UI thread form.Label.Text = newText; }); // Back on the worker thread 

Notez que Invoke bloque l’exécution jusqu’à la fin – c’est du code synchrone. La question ne concerne pas le code asynchrone, mais il y a beaucoup de contenu sur Stack Overflow à propos de l’écriture du code asynchrone lorsque vous voulez en savoir plus.

Manipulation de long travail

Depuis .NET 4.5 et C # 5.0, vous devez utiliser le modèle asynchrone basé sur les tâches (TAP) avec asyncattendre des mots-clés dans toutes les zones (y compris l’interface graphique):

TAP est le modèle de conception asynchrone recommandé pour les nouveaux développements

au lieu du modèle de programmation asynchrone (APM) et du modèle asynchrone basé sur événement (EAP) (ce dernier inclut la classe BackgroundWorker ).

Ensuite, la solution recommandée pour les nouveaux développements est la suivante:

  1. Implémentation asynchrone d’un gestionnaire d’événement (Oui, c’est tout):

     private async void Button_Clicked(object sender, EventArgs e) { var progress = new Progress(s => label.Text = s); await Task.Factory.StartNew(() => SecondThreadConcern.LongWork(progress), TaskCreationOptions.LongRunning); label.Text = "completed"; } 
  2. Implémentation du deuxième thread qui notifie le thread d’interface utilisateur:

     class SecondThreadConcern { public static void LongWork(IProgress progress) { // Perform a long running work... for (var i = 0; i < 10; i++) { Task.Delay(500).Wait(); progress.Report(i.ToString()); } } } 

Notez ce qui suit:

  1. Code court et propre écrit de manière séquentielle sans callbacks et threads explicites.
  2. Tâche au lieu de thread .
  3. Le mot-clé async , qui permet d’utiliser wait, empêche à son tour le gestionnaire d’événements d’atteindre l’état d’achèvement jusqu’à la fin de la tâche et, en attendant, ne bloque pas le thread de l’interface utilisateur.
  4. Classe de progression (voir Interface IProgress ) qui prend en charge le principe de conception de la séparation des préoccupations (SoC) et ne nécessite pas de répartiteur explicite ni d’appel. Il utilise le SynchronizationContext actuel depuis son emplacement de création (ici le thread d'interface utilisateur).
  5. TaskCreationOptions.LongRunning qui suggère de ne pas mettre la tâche en queue dans ThreadPool .

Pour des exemples plus verbeux, voir: L'avenir de C #: Les bonnes choses arrivent à ceux qui «attendent» de Joseph Albahari .

Voir également le concept de modèle de threading d'interface utilisateur .

Gestion des exceptions

L'extrait de code ci-dessous montre comment gérer les exceptions et activer la propriété Enabled du bouton pour empêcher plusieurs clics lors de l'exécution en arrière-plan.

 private async void Button_Click(object sender, EventArgs e) { button.Enabled = false; try { var progress = new Progress(s => button.Text = s); await Task.Run(() => SecondThreadConcern.FailingWork(progress)); button.Text = "Completed"; } catch(Exception exception) { button.Text = "Failed: " + exception.Message; } button.Enabled = true; } class SecondThreadConcern { public static void FailingWork(IProgress progress) { progress.Report("I will fail in..."); Task.Delay(500).Wait(); for (var i = 0; i < 3; i++) { progress.Report((3 - i).ToString()); Task.Delay(500).Wait(); } throw new Exception("Oops..."); } } 

Variation de la solution la plus simple de Marc Gravell pour .NET 4:

 control.Invoke((MethodInvoker) (() => control.Text = "new text")); 

Ou utilisez plutôt délégué d’Action:

 control.Invoke(new Action(() => control.Text = "new text")); 

Voir ici pour une comparaison des deux: MethodInvoker vs Action for Control.BeginInvoke

Méthode d’extinction d’incendie et d’oubli pour .NET 3.5+

 using System; using System.Windows.Forms; public static class ControlExtensions { ///  /// Executes the Action asynchronously on the UI thread, does not block execution on the calling thread. ///  ///  ///  public static void UIThread(this Control @this, Action code) { if (@this.InvokeRequired) { @this.BeginInvoke(code); } else { code.Invoke(); } } } 

Cela peut être appelé en utilisant la ligne de code suivante:

 this.UIThread(() => this.myLabel.Text = "Text Goes Here"); 

C’est la façon classique de faire ceci:

 using System; using System.Windows.Forms; using System.Threading; namespace Test { public partial class UIThread : Form { Worker worker; Thread workerThread; public UIThread() { InitializeComponent(); worker = new Worker(); worker.ProgressChanged += new EventHandler(OnWorkerProgressChanged); workerThread = new Thread(new ThreadStart(worker.StartWork)); workerThread.Start(); } private void OnWorkerProgressChanged(object sender, ProgressChangedArgs e) { // Cross thread - so you don't get the cross-threading exception if (this.InvokeRequired) { this.BeginInvoke((MethodInvoker)delegate { OnWorkerProgressChanged(sender, e); }); return; } // Change control this.label1.Text = e.Progress; } } public class Worker { public event EventHandler ProgressChanged; protected void OnProgressChanged(ProgressChangedArgs e) { if(ProgressChanged!=null) { ProgressChanged(this,e); } } public void StartWork() { Thread.Sleep(100); OnProgressChanged(new ProgressChangedArgs("Progress Changed")); Thread.Sleep(100); } } public class ProgressChangedArgs : EventArgs { public ssortingng Progress {get;private set;} public ProgressChangedArgs(ssortingng progress) { Progress = progress; } } } 

Votre thread de travail a un événement. Votre thread d’interface utilisateur démarre un autre thread pour effectuer le travail et connecte cet événement de travail afin que vous puissiez afficher l’état du thread de travail.

Ensuite, dans l’interface utilisateur, vous devez croiser les threads pour modifier le contrôle actuel … comme une étiquette ou une barre de progression.

La solution simple consiste à utiliser Control.Invoke .

 void DoSomething() { if (InvokeRequired) { Invoke(new MethodInvoker(updateGUI)); } else { // Do Something updateGUI(); } } void updateGUI() { // update gui here } 

Le code de thread est souvent bogué et toujours difficile à tester. Vous n’avez pas besoin d’écrire du code de thread pour mettre à jour l’interface utilisateur à partir d’une tâche en arrière-plan. Utilisez simplement la classe BackgroundWorker pour exécuter la tâche et sa méthode ReportProgress pour mettre à jour l’interface utilisateur. En général, vous ne déclarez qu’un pourcentage complet, mais il y a une autre surcharge qui inclut un object d’état. Voici un exemple qui ne fait que signaler un object chaîne:

  private void button1_Click(object sender, EventArgs e) { backgroundWorker1.WorkerReportsProgress = true; backgroundWorker1.RunWorkerAsync(); } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { Thread.Sleep(5000); backgroundWorker1.ReportProgress(0, "A"); Thread.Sleep(5000); backgroundWorker1.ReportProgress(0, "B"); Thread.Sleep(5000); backgroundWorker1.ReportProgress(0, "C"); } private void backgroundWorker1_ProgressChanged( object sender, ProgressChangedEventArgs e) { label1.Text = e.UserState.ToSsortingng(); } 

C’est bien si vous voulez toujours mettre à jour le même champ. Si vous avez des mises à jour plus compliquées à faire, vous pouvez définir une classe pour représenter l’état de l’interface utilisateur et la transmettre à la méthode ReportProgress.

Une dernière chose, assurez-vous de définir l’indicateur WorkerReportsProgress ou la méthode ReportProgress sera complètement ignorée.

La grande majorité des réponses utilise Control.Invoke qui est une condition de course en attente . Par exemple, considérons la réponse acceptée:

 ssortingng newText = "abc"; // running on worker thread this.Invoke((MethodInvoker)delegate { someLabel.Text = newText; // runs on UI thread }); 

Si l’utilisateur ferme le formulaire juste avant l’ this.Invoke (rappelez-vous this s’agit de l’object Form ), une ObjectDisposedException sera probablement déclenchée.

La solution consiste à utiliser SynchronizationContext , en particulier SynchronizationContext.Current comme le suggère hamilton.danielb (les autres réponses reposent sur des implémentations spécifiques de SynchronizationContext qui ne sont absolument pas nécessaires). Je modifierais légèrement son code pour utiliser SynchronizationContext.Post plutôt que SynchronizationContext.Send (car le thread de travail n’a généralement pas besoin d’attendre):

 public partial class MyForm : Form { private readonly SynchronizationContext _context; public MyForm() { _context = SynchronizationContext.Current ... } private MethodOnOtherThread() { ... _context.Post(status => someLabel.Text = newText,null); } } 

Notez que sur .NET 4.0 et versions ultérieures, vous devriez vraiment utiliser des tâches pour les opérations asynchrones. Voir la réponse de n-san pour l’approche basée sur des tâches équivalentes (en utilisant TaskScheduler.FromCurrentSynchronizationContext ).

Enfin, sur .NET 4.5 et versions ultérieures, vous pouvez également utiliser Progress (qui capture en gros SynchronizationContext.Current lors de sa création) comme démontré par Ryszard Dżegan dans les cas où l’opération longue nécessite l’exécution du code tout en travaillant.

Vous devrez vous assurer que la mise à jour se produit sur le thread approprié; le fil de l’interface utilisateur.

Pour ce faire, vous devrez appeler le gestionnaire d’événements au lieu de l’appeler directement.

Vous pouvez le faire en soulevant votre événement comme ceci:

(Le code est tapé ici de ma tête, donc je n’ai pas vérifié la syntaxe correcte, etc., mais cela devrait vous aider.)

 if( MyEvent != null ) { Delegate[] eventHandlers = MyEvent.GetInvocationList(); foreach( Delegate d in eventHandlers ) { // Check whether the target of the delegate implements // ISynchronizeInvoke (Winforms controls do), and see // if a context-switch is required. ISynchronizeInvoke target = d.Target as ISynchronizeInvoke; if( target != null && target.InvokeRequired ) { target.Invoke (d, ... ); } else { d.DynamicInvoke ( ... ); } } } 

Notez que le code ci-dessus ne fonctionnera pas sur les projets WPF, car les contrôles WPF ISynchronizeInvoke pas l’interface ISynchronizeInvoke .

Pour vous assurer que le code ci-dessus fonctionne avec Windows Forms et WPF, ainsi que toutes les autres plates-formes, vous pouvez consulter les AsyncOperation , AsyncOperationManager et SynchronizationContext .

Afin de déclencher facilement des événements de cette façon, j’ai créé une méthode d’extension, ce qui me permet de simplifier la génération d’un événement en appelant simplement:

 MyEvent.Raise(this, EventArgs.Empty); 

Bien sûr, vous pouvez également utiliser la classe BackGroundWorker, qui résumera cette question pour vous.

Vous devrez appeler la méthode sur le thread d’interface graphique. Vous pouvez le faire en appelant Control.Invoke.

Par exemple:

 delegate void UpdateLabelDelegate (ssortingng message); void UpdateLabel (ssortingng message) { if (InvokeRequired) { Invoke (new UpdateLabelDelegate (UpdateLabel), message); return; } MyLabelControl.Text = message; } 

En raison de la sortingvialité du scénario, j’aurais en fait le sondage de thread d’interface utilisateur pour le statut. Je pense que vous constaterez que cela peut être assez élégant.

 public class MyForm : Form { private volatile ssortingng m_Text = ""; private System.Timers.Timer m_Timer; private MyForm() { m_Timer = new System.Timers.Timer(); m_Timer.SynchronizingObject = this; m_Timer.Interval = 1000; m_Timer.Elapsed += (s, a) => { MyProgressLabel.Text = m_Text; }; m_Timer.Start(); var thread = new Thread(WorkerThread); thread.Start(); } private void WorkerThread() { while (...) { // Periodically publish progress information. m_Text = "Still working..."; } } } 

Cette approche évite l’opération de marshaling requirejse lors de l’utilisation des méthodes ISynchronizeInvoke.Invoke et ISynchronizeInvoke.BeginInvoke . Il n’y a rien de mal à utiliser la technique de marshaling, mais vous devez être conscient de quelques mises en garde.

  • Assurez-vous de ne pas appeler BeginInvoke trop souvent ou de dépasser la pompe à messages.
  • L’appel Invoke sur le thread de travail est un appel bloquant. Cela arrêtera temporairement le travail effectué dans ce fil.

La stratégie que je propose dans cette réponse inverse les rôles de communication des threads. Au lieu du thread de travail qui envoie les données, le thread d’interface utilisateur l’interroge. Ceci est un modèle commun utilisé dans de nombreux scénarios. Comme tout ce que vous voulez faire, c’est afficher les informations de progression à partir du thread de travail, je pense que vous constaterez que cette solution est une excellente alternative à la solution de marshaling. Il présente les avantages suivants.

  • L’interface utilisateur et les threads de travail restnt faiblement couplés, contrairement à l’approche Control.Invoke ou Control.BeginInvoke qui les couple étroitement.
  • Le thread d’interface utilisateur n’empêche pas la progression du thread de travail.
  • Le thread de travail ne peut pas dominer l’heure à laquelle le thread d’interface utilisateur passe à jour.
  • Les intervalles auxquels les interfaces utilisateur et les threads de travail effectuent des opérations peuvent restr indépendants.
  • Le thread de travail ne peut pas surcharger la pompe à messages du thread d’interface utilisateur.
  • Le thread d’interface utilisateur dicte quand et à quelle fréquence l’interface utilisateur est mise à jour.

Aucun élément d’invocation dans les réponses précédentes n’est nécessaire.

Vous devez regarder WindowsFormsSynchronizationContext:

 // In the main thread WindowsFormsSynchronizationContext mUiContext = new WindowsFormsSynchronizationContext(); ... // In some non-UI Thread // Causes an update in the GUI thread. mUiContext.Post(UpdateGUI, userData); ... void UpdateGUI(object userData) { // Update your GUI controls here } 

Pour de nombreuses raisons, c’est aussi simple que cela:

 public delegate void serviceGUIDelegate(); private void updateGUI() { this.Invoke(new serviceGUIDelegate(serviceGUI)); } 

“serviceGUI ()” est une méthode de niveau graphique dans le formulaire (this) qui peut changer autant de contrôles que vous le souhaitez. Appelez “updateGUI ()” depuis l’autre thread. Des parameters peuvent être ajoutés pour transmettre des valeurs ou (probablement plus rapidement) utiliser des variables d’étendue de classe avec des verrous sur elles, s’il ya un risque de conflit entre les threads accédant à celles-ci et pouvant provoquer une instabilité. Utilisez BeginInvoke au lieu de Invoke si le thread non-GUI est critique dans le temps (en gardant à l’esprit l’avertissement de Brian Gideon).

Ceci dans ma variante C # 3.0 de la solution de Ian Kemp:

 public static void SetPropertyInGuiThread(this C control, Expression> property, V value) where C : Control { var memberExpression = property.Body as MemberExpression; if (memberExpression == null) throw new ArgumentException("The 'property' expression must specify a property on the control."); var propertyInfo = memberExpression.Member as PropertyInfo; if (propertyInfo == null) throw new ArgumentException("The 'property' expression must specify a property on the control."); if (control.InvokeRequired) control.Invoke( (Action>, V>)SetPropertyInGuiThread, new object[] { control, property, value } ); else propertyInfo.SetValue(control, value, null); } 

Vous l’appelez comme ceci:

 myButton.SetPropertyInGuiThread(b => b.Text, "Click Me!") 
  1. Il ajoute une vérification null au résultat du “as MemberExpression”.
  2. Il améliore la sécurité de type statique.

Sinon, l’original est une très bonne solution.

Celui-ci est similaire à la solution ci-dessus utilisant .NET Framework 3.0, mais il a résolu le problème de la prise en charge de la sécurité au moment de la compilation .

 public static class ControlExtension { delegate void SetPropertyValueHandler(Control souce, Expression> selector, TResult value); public static void SetPropertyValue(this Control source, Expression> selector, TResult value) { if (source.InvokeRequired) { var del = new SetPropertyValueHandler(SetPropertyValue); source.Invoke(del, new object[]{ source, selector, value}); } else { var propInfo = ((MemberExpression)selector.Body).Member as PropertyInfo; propInfo.SetValue(source, value, null); } } } 

Utiliser:

 this.lblTimeDisplay.SetPropertyValue(a => a.Text, "some ssortingng"); this.lblTimeDisplay.SetPropertyValue(a => a.Visible, false); 

Le compilateur échouera si l’utilisateur passe le type de données incorrect.

 this.lblTimeDisplay.SetPropertyValue(a => a.Visible, "sometext"); 

Salvete! Après avoir recherché cette question, j’ai trouvé les réponses de FrankG et Oregon Ghost les plus faciles à utiliser. Maintenant, je code en Visual Basic et a exécuté cet extrait via un convertisseur; donc je ne sais pas trop comment ça se passe.

J’ai un formulaire de dialog appelé form_Diagnostics, qui contient une zone richtext, appelée updateDiagWindow, que j’utilise comme une sorte d’affichage de journalisation. Je devais pouvoir mettre à jour son texte à partir de tous les threads. Les lignes supplémentaires permettent à la fenêtre de défiler automatiquement vers les lignes les plus récentes.

Et donc, je peux maintenant mettre à jour l’affichage avec une ligne, de n’importe où dans le programme entier, de la manière qui, selon vous, fonctionnerait sans aucun thread:

  form_Diagnostics.updateDiagWindow(whatmessage); 

Code principal (mettez ceci à l’intérieur du code de classe de votre formulaire):

 #region "---------Update Diag Window Text------------------------------------" // This sub allows the diag window to be updated by all threads public void updateDiagWindow(ssortingng whatmessage) { var _with1 = diagwindow; if (_with1.InvokeRequired) { _with1.Invoke(new UpdateDiagDelegate(UpdateDiag), whatmessage); } else { UpdateDiag(whatmessage); } } // This next line makes the private UpdateDiagWindow available to all threads private delegate void UpdateDiagDelegate(ssortingng whatmessage); private void UpdateDiag(ssortingng whatmessage) { var _with2 = diagwindow; _with2.appendtext(whatmessage); _with2.SelectionStart = _with2.Text.Length; _with2.ScrollToCaret(); } #endregion 
 Label lblText; //initialized elsewhere void AssignLabel(ssortingng text) { if (InvokeRequired) { BeginInvoke((Action)AssignLabel, text); return; } lblText.Text = text; } 

Notez que BeginInvoke() est préférable à Invoke() car il est moins susceptible de provoquer des blocages (toutefois, cela ne pose pas de problème lorsque vous assignez du texte à une étiquette):

Lorsque vous utilisez Invoke() vous attendez le retour de la méthode. Maintenant, il se peut que vous fassiez quelque chose dans le code invoqué qui devra attendre le thread, ce qui peut ne pas être immédiatement évident s’il est enterré dans certaines fonctions que vous appelez, ce qui peut se produire indirectement via des gestionnaires d’événements. Donc, vous attendez le sujet, le sujet vous attend et vous êtes bloqué.

Cela a effectivement causé la suspension de certains de nos logiciels. Il était assez facile de corriger en remplaçant Invoke() par BeginInvoke() . Sauf si vous avez besoin d’une opération synchrone, ce qui peut être le cas si vous avez besoin d’une valeur de retour, utilisez BeginInvoke() .

Lorsque j’ai rencontré le même problème, j’ai demandé de l’aide à Google, mais plutôt que de me donner une solution simple, cela m’a MethodInvoker davantage en donnant des exemples de MethodInvoker et de blah blah blah. J’ai donc décidé de le résoudre moi-même. Voici ma solution:

Faites un délégué comme ceci:

 Public delegate void LabelDelegate(ssortingng s); void Updatelabel(ssortingng text) { if (label.InvokeRequired) { LabelDelegate LDEL = new LabelDelegate(Updatelabel); label.Invoke(LDEL, text); } else label.Text = text } 

You can call this function in a new thread like this

 Thread th = new Thread(() => Updatelabel("Hello World")); th.start(); 

Don’t be confused with Thread(() => .....) . I use an anonymous function or lambda expression when I work on a thread. To reduce the lines of code you can use the ThreadStart(..) method too which I am not supposed to explain here.

Simply use something like this:

  this.Invoke((MethodInvoker)delegate { progressBar1.Value = e.ProgressPercentage; // runs on UI thread }); 

You may use the already-existing delegate Action :

 private void UpdateMethod() { if (InvokeRequired) { Invoke(new Action(UpdateMethod)); } } 

My version is to insert one line of recursive “mantra”:

For no arguments:

  void Aaaaaaa() { if (InvokeRequired) { Invoke(new Action(Aaaaaaa)); return; } //1 line of mantra // Your code! } 

For a function that has arguments:

  void Bbb(int x, ssortingng text) { if (InvokeRequired) { Invoke(new Action(Bbb), new[] { x, text }); return; } // Your code! } 

THAT is IT .


Some argumentation : Usually it is bad for code readability to put {} after an if () statement in one line. But in this case it is routine all-the-same “mantra”. It doesn’t break code readability if this method is consistent over the project. And it saves your code from littering (one line of code instead of five).

As you see if(InvokeRequired) {something long} you just know “this function is safe to call from another thread”.

You must use invoke and delegate

 private delegate void MyLabelDelegate(); label1.Invoke( new MyLabelDelegate(){ label1.Text += 1; }); 

Try to refresh the label using this

 public static class ExtensionMethods { private static Action EmptyDelegate = delegate() { }; public static void Refresh(this UIElement uiElement) { uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate); } } 

Create a class variable:

 SynchronizationContext _context; 

Set it in the constructor that creates your UI:

 var _context = SynchronizationContext.Current; 

When you want to update the label:

 _context.Send(status =>{ // UPDATE LABEL }, null); 

The easiest way I think:

  void Update() { BeginInvoke((Action)delegate() { //do your update }); } 

For example, access a control other than in the current thread:

 Speed_Threshold = 30; textOutput.Invoke(new EventHandler(delegate { lblThreshold.Text = Speed_Threshold.ToSsortingng(); })); 

There the lblThreshold is a Label and Speed_Threshold is a global variable.

When you’re in the UI thread you could ask it for its synchronization context task scheduler. It would give you a TaskScheduler that schedules everything on the UI thread.

Then you can chain your tasks so that when the result is ready then another task (which is scheduled on the UI thread) picks it and assigns it to a label.

 public partial class MyForm : Form { private readonly TaskScheduler _uiTaskScheduler; public MyForm() { InitializeComponent(); _uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); } private void buttonRunAsyncOperation_Click(object sender, EventArgs e) { RunAsyncOperation(); } private void RunAsyncOperation() { var task = new Task(LengthyComputation); task.ContinueWith(antecedent => UpdateResultLabel(antecedent.Result), _uiTaskScheduler); task.Start(); } private ssortingng LengthyComputation() { Thread.Sleep(3000); return "47"; } private void UpdateResultLabel(ssortingng text) { labelResult.Text = text; } } 

This works for tasks (not threads) which are the preferred way of writing concurrent code now .

I just read the answers and this appears to be a very hot topic. I’m currently using .NET 3.5 SP1 and Windows Forms.

The well-known formula greatly described in the previous answers that makes use of the InvokeRequired property covers most of the cases, but not the entire pool.

What if the Handle has not been created yet?

The InvokeRequired property, as described here (Control.InvokeRequired Property reference to MSDN) returns true if the call was made from a thread that is not the GUI thread, false either if the call was made from the GUI thread, or if the Handle was not created yet.

You can come across an exception if you want to have a modal form shown and updated by another thread. Because you want that form shown modally, you could do the following:

 private MyForm _gui; public void StartToDoThings() { _gui = new MyForm(); Thread thread = new Thread(SomeDelegate); thread.Start(); _gui.ShowDialog(); } 

And the delegate can update a Label on the GUI:

 private void SomeDelegate() { // Operations that can take a variable amount of time, even no time //... then you update the GUI if(_gui.InvokeRequired) _gui.Invoke((Action)delegate { _gui.Label1.Text = "Done!"; }); else _gui.Label1.Text = "Done!"; } 

This can cause an InvalidOperationException if the operations before the label’s update “take less time” (read it and interpret it as a simplification) than the time it takes for the GUI thread to create the Form ‘s Handle . This happens within the ShowDialog() method.

You should also check for the Handle like this:

 private void SomeDelegate() { // Operations that can take a variable amount of time, even no time //... then you update the GUI if(_gui.IsHandleCreated) // <---- ADDED if(_gui.InvokeRequired) _gui.Invoke((Action)delegate { _gui.Label1.Text = "Done!"; }); else _gui.Label1.Text = "Done!"; } 

You can handle the operation to perform if the Handle has not been created yet: You can just ignore the GUI update (like shown in the code above) or you can wait (more risky). This should answer the question.

Optional stuff: Personally I came up coding the following:

 public class ThreadSafeGuiCommand { private const int SLEEPING_STEP = 100; private readonly int _totalTimeout; private int _timeout; public ThreadSafeGuiCommand(int totalTimeout) { _totalTimeout = totalTimeout; } public void Execute(Form form, Action guiCommand) { _timeout = _totalTimeout; while (!form.IsHandleCreated) { if (_timeout <= 0) return; Thread.Sleep(SLEEPING_STEP); _timeout -= SLEEPING_STEP; } if (form.InvokeRequired) form.Invoke(guiCommand); else guiCommand(); } } 

I feed my forms that get updated by another thread with an instance of this ThreadSafeGuiCommand , and I define methods that update the GUI (in my Form) like this:

 public void SetLabeTextTo(ssortingng value) { _threadSafeGuiCommand.Execute(this, delegate { Label1.Text = value; }); } 

In this way I'm quite sure that I will have my GUI updated whatever thread will make the call, optionally waiting for a well-defined amount of time (the timeout).

I wanted to add a warning because I noticed that some of the simple solutions omit the InvokeRequired check.

I noticed that if your code executes before the window handle of the control has been created (eg before the form is shown), Invoke throws an exception. So I recommend always checking on InvokeRequired before calling Invoke or BeginInvoke .