How do I update the GUI from another thread?
Asked Answered
F

47

1591

Which is the simplest way to update a Label from another Thread?

  • I have a Form running on thread1, and from that I'm starting another thread (thread2).

  • While thread2 is processing some files I would like to update a Label on the Form with the current status of thread2's work.

How could I do that?

Floriated answered 19/3, 2009 at 9:37 Comment(6)
Doesn't .net 2.0+ have the BackgroundWorker class just for this. It UI thread aware. 1. Create a BackgroundWorker 2. Add two delegates (one for processing, and one for completion)Karleen
maybe a little late : codeproject.com/KB/cs/Threadsafe_formupdating.aspxPerturb
See the answer for .NET 4.5 and C# 5.0: https://mcmap.net/q/17422/-how-do-i-update-the-gui-from-another-threadBathilda
This question does not apply to Gtk# GUI. For Gtk# see this and this answer.Another
Beware: the answers on this question are now a cluttered mess of OT ("here's what I did for my WPF app") and historical .NET 2.0 artifacts.Scholasticate
Related post - Force GUI update from UI ThreadNutwood
C
824

For .NET 2.0, here's a nice bit of code I wrote that does exactly what you want, and works for any property on a Control:

private delegate void SetControlPropertyThreadSafeDelegate(
    Control control, 
    string propertyName, 
    object propertyValue);

public static void SetControlPropertyThreadSafe(
    Control control, 
    string 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 });
  }
}

Call it like this:

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

If you're using .NET 3.0 or above, you could rewrite the above method as an extension method of the Control class, which would then simplify the call to:

myLabel.SetPropertyThreadSafe("Text", status);

UPDATE 05/10/2010:

For .NET 3.0 you should use this code:

private delegate void SetPropertyThreadSafeDelegate<TResult>(
    Control @this, 
    Expression<Func<TResult>> property, 
    TResult value);

public static void SetPropertyThreadSafe<TResult>(
    this Control @this, 
    Expression<Func<TResult>> property, 
    TResult value)
{
  var propertyInfo = (property.Body as MemberExpression).Member 
      as PropertyInfo;

  if (propertyInfo == null ||
      [email protected]().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<TResult> 
      (SetPropertyThreadSafe), 
      new object[] { @this, property, value });
  }
  else
  {
      @this.GetType().InvokeMember(
          propertyInfo.Name, 
          BindingFlags.SetProperty, 
          null, 
          @this, 
          new object[] { value });
  }
}

which uses LINQ and lambda expressions to allow much cleaner, simpler and safer syntax:

// status has to be of type string or this will fail to compile
myLabel.SetPropertyThreadSafe(() => myLabel.Text, status);

Not only is the property name now checked at compile time, the property's type is as well, so it's impossible to (for example) assign a string value to a boolean property, and hence cause a runtime exception.

Unfortunately this doesn't stop anyone from doing stupid things such as passing in another Control's property and value, so the following will happily compile:

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

Hence I added the runtime checks to ensure that the passed-in property does actually belong to the Control that the method's being called on. Not perfect, but still a lot better than the .NET 2.0 version.

If anyone has any further suggestions on how to improve this code for compile-time safety, please comment!

Celisse answered 19/3, 2009 at 10:37 Comment(8)
There are cases when this.GetType() evaluates to the same as propertyInfo.ReflectedType (e.g. LinkLabel on WinForms). I don't have a large C# experience, but I think that the condition for exception should be: if (propertyInfo == null || ([email protected]().IsSubclassOf(propertyInfo.ReflectedType) && @this.GetType() != propertyInfo.ReflectedType) || @this.GetType().GetProperty(propertyInfo.Name, propertyInfo.PropertyType) == null)Gesticulation
@lan can this SetControlPropertyThreadSafe(myLabel, "Text", status) be called from another module or class or formVampire
I've gone back to using this because ironically BGWorker freezes the UI thread Actually I am happy with the v2 version... thanks....Lichee
The solution provided is unnecessarily complex. See Marc Gravell's solution, or Zaid Masud's solution, if you value simplicity.Lisandralisbeth
This solution does waste ton's of resources if you update multiple properties as every Invoke costs a lot of resources. I don't think this is how the feature of Thread Safety was intended anyway. Do Encapsulte your UI update actions and Invoke it ONCE (and not per property)Constraint
You must have been exaggerated a bit, or Microsoft have done it wrong! for me as new c# programmer, it is so complex! and doesn't look like nice bit of code for meBatsman
Why on earth would you use this code over the BackgroundWorker component?Medulla
This code is horrible and likely slow compared to alternative methods due to it's use of reflection.Scissure
B
1217

The simplest way is an anonymous method passed into Label.Invoke:

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

Notice that Invoke blocks execution until it completes--this is synchronous code. The question doesn't ask about asynchronous code, but there is lots of content on Stack Overflow about writing asynchronous code when you want to learn about it.

Bashuk answered 19/3, 2009 at 10:17 Comment(9)
But, then your processing function must be a member method of your GUI form ?Themistocles
Seeing as the OP hasn't mentioned any class/instance except the form, that isn't a bad default...Bashuk
Don't forget the "this" keyword is referencing a "Control" class.Ruck
@MarcGravell but don't you need to do 'if invokeRequired' first?Maceio
@Maceio it is safe either way, and we already know we're on a worker, so why check something we know?Bashuk
You should use InvokeRequired and the anonymous delegate at the begining of the method like it shown in Hatth answerSatire
@Satire not really - one of the point of using this method is that you already know which parts run on the worker, and which run on the UI thread. No need to check.Bashuk
@MarcGravell it's a brilliant solution, how did u find out using an anonymous method runs on the main thread?Shivaree
@John because that is what Control.Invoke does with any delegate - not just anon methodsBashuk
C
824

For .NET 2.0, here's a nice bit of code I wrote that does exactly what you want, and works for any property on a Control:

private delegate void SetControlPropertyThreadSafeDelegate(
    Control control, 
    string propertyName, 
    object propertyValue);

public static void SetControlPropertyThreadSafe(
    Control control, 
    string 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 });
  }
}

Call it like this:

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

If you're using .NET 3.0 or above, you could rewrite the above method as an extension method of the Control class, which would then simplify the call to:

myLabel.SetPropertyThreadSafe("Text", status);

UPDATE 05/10/2010:

For .NET 3.0 you should use this code:

private delegate void SetPropertyThreadSafeDelegate<TResult>(
    Control @this, 
    Expression<Func<TResult>> property, 
    TResult value);

public static void SetPropertyThreadSafe<TResult>(
    this Control @this, 
    Expression<Func<TResult>> property, 
    TResult value)
{
  var propertyInfo = (property.Body as MemberExpression).Member 
      as PropertyInfo;

  if (propertyInfo == null ||
      [email protected]().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<TResult> 
      (SetPropertyThreadSafe), 
      new object[] { @this, property, value });
  }
  else
  {
      @this.GetType().InvokeMember(
          propertyInfo.Name, 
          BindingFlags.SetProperty, 
          null, 
          @this, 
          new object[] { value });
  }
}

which uses LINQ and lambda expressions to allow much cleaner, simpler and safer syntax:

// status has to be of type string or this will fail to compile
myLabel.SetPropertyThreadSafe(() => myLabel.Text, status);

Not only is the property name now checked at compile time, the property's type is as well, so it's impossible to (for example) assign a string value to a boolean property, and hence cause a runtime exception.

Unfortunately this doesn't stop anyone from doing stupid things such as passing in another Control's property and value, so the following will happily compile:

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

Hence I added the runtime checks to ensure that the passed-in property does actually belong to the Control that the method's being called on. Not perfect, but still a lot better than the .NET 2.0 version.

If anyone has any further suggestions on how to improve this code for compile-time safety, please comment!

Celisse answered 19/3, 2009 at 10:37 Comment(8)
There are cases when this.GetType() evaluates to the same as propertyInfo.ReflectedType (e.g. LinkLabel on WinForms). I don't have a large C# experience, but I think that the condition for exception should be: if (propertyInfo == null || ([email protected]().IsSubclassOf(propertyInfo.ReflectedType) && @this.GetType() != propertyInfo.ReflectedType) || @this.GetType().GetProperty(propertyInfo.Name, propertyInfo.PropertyType) == null)Gesticulation
@lan can this SetControlPropertyThreadSafe(myLabel, "Text", status) be called from another module or class or formVampire
I've gone back to using this because ironically BGWorker freezes the UI thread Actually I am happy with the v2 version... thanks....Lichee
The solution provided is unnecessarily complex. See Marc Gravell's solution, or Zaid Masud's solution, if you value simplicity.Lisandralisbeth
This solution does waste ton's of resources if you update multiple properties as every Invoke costs a lot of resources. I don't think this is how the feature of Thread Safety was intended anyway. Do Encapsulte your UI update actions and Invoke it ONCE (and not per property)Constraint
You must have been exaggerated a bit, or Microsoft have done it wrong! for me as new c# programmer, it is so complex! and doesn't look like nice bit of code for meBatsman
Why on earth would you use this code over the BackgroundWorker component?Medulla
This code is horrible and likely slow compared to alternative methods due to it's use of reflection.Scissure
S
467

Handling long work

Since .NET 4.5 and C# 5.0 you should use Task-based Asynchronous Pattern (TAP) along with async-await keywords in all areas (including the GUI):

TAP is the recommended asynchronous design pattern for new development

instead of Asynchronous Programming Model (APM) and Event-based Asynchronous Pattern (EAP) (the latter includes the BackgroundWorker Class).

Then, the recommended solution for new development is:

  1. Asynchronous implementation of an event handler (Yes, that's all):

     private async void Button_Clicked(object sender, EventArgs e)
     {
         var progress = new Progress<string>(s => label.Text = s);
         await Task.Factory.StartNew(() => SecondThreadConcern.LongWork(progress),
                                     TaskCreationOptions.LongRunning);
         label.Text = "completed";
     }
    
  2. Implementation of the second thread that notifies the UI thread:

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

Notice the following:

  1. Short and clean code written in sequential manner without callbacks and explicit threads.
  2. Task instead of Thread.
  3. async keyword, that allows to use await which in turn prevent the event handler from reaching the completion state till the task finished and in the meantime doesn't block the UI thread.
  4. Progress class (see IProgress Interface) that supports Separation of Concerns (SoC) design principle and doesn't require explicit dispatcher and invoking. It uses the current SynchronizationContext from its creation place (here the UI thread).
  5. TaskCreationOptions.LongRunning that hints to do not queue the task into ThreadPool.

For a more verbose examples see: The Future of C#: Good things come to those who 'await' by Joseph Albahari.

See also about UI Threading Model concept.

Handling exceptions

The below snippet is an example of how to handle exceptions and toggle button's Enabled property to prevent multiple clicks during background execution.

private async void Button_Click(object sender, EventArgs e)
{
    button.Enabled = false;

    try
    {
        var progress = new Progress<string>(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<string> 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...");
    }
}
Smooth answered 3/8, 2013 at 13:9 Comment(12)
If SecondThreadConcern.LongWork() throws an exception, can it be caught by the UI thread? This is an excellent post, btw.Traci
I have added an additional section to the answer to fulfil your requirements. Regards.Bathilda
The ExceptionDispatchInfo class is responsible for that miracle of rethrowing background exception on UI thread in async-await pattern.Bathilda
Is it just me in thinking that this way of doing this is way more verbose than just invoking Invoke/Begin?!Recrudescence
According to YAGNI and KISS principles, you should use the simplest and most legible solution. If Invoke meets your needs and your code base is small, then you can violate SoC without perceptible loss for the favor of productivity and ease. Then, when your source code becomes larger and harder to maintain, you can always refactor it to introduce the SoC (assuming you have reliable regression tests).Bathilda
Task.Delay(500).Wait()? What's the point of creating a Task to just block the current thread? You should never block a thread pool thread!Ferry
The async-await pattern is only good for simple problems. Try it on a more complex code and you'll have headaches for life.Kalgoorlie
should and recommended are two different thingsGear
@Yarik, they are simulating a long running thread. In Actual Scenario content of second thread would be different except the line that is called to update UIGear
@AaA, it still doesn't make sense to use Task.Delay here, even after 6 years. Use Thread.Sleep.Ferry
In this context they do the same thing, but Delay is preferred according to a comment on this postGear
Not with Wait(). Task.Delay is heavily preferred with async code, but Task.Wait() isn't async. It blocks the calling thread and does not yield.Bouncing
C
274

Variation of Marc Gravell's simplest solution for .NET 4:

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

Or use Action delegate instead:

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

See here for a comparison of the two: MethodInvoker vs Action for Control.BeginInvoke

Compilation answered 29/5, 2012 at 18:51 Comment(5)
what is 'control' in this example? My UI control? Trying to implement this in WPF on a label control, and Invoke is not a member of my label.Babysit
What's about extension method like @styxriver https://mcmap.net/q/17422/-how-do-i-update-the-gui-from-another-thread ?Verse
declare 'Action y;' inside the class or method changing the text property and update the text with this piece of code 'yourcontrol.Invoke(y=() => yourcontrol.Text = "new text");'Deuterium
@Babysit it's not a member because it's only for WinForms. For WPF you use Dispatcher.InvokeKinchen
I was following this solution but sometimes my UI was not getting updated. I found that i need this.refresh() to force invalidate and repaint the GUI .. if it is helpful ..Relevance
C
154

Fire and forget extension method for .NET 3.5+

using System;
using System.Windows.Forms;

public static class ControlExtensions
{
    /// <summary>
    /// Executes the Action asynchronously on the UI thread, does not block execution on the calling thread.
    /// </summary>
    /// <param name="control"></param>
    /// <param name="code"></param>
    public static void UIThread(this Control @this, Action code)
    {
        if (@this.InvokeRequired)
        {
            @this.BeginInvoke(code);
        }
        else
        {
            code.Invoke();
        }
    }
}

This can be called using the following line of code:

this.UIThread(() => this.myLabel.Text = "Text Goes Here");
Cyrus answered 27/8, 2010 at 21:10 Comment(7)
What's the point of the @this usage? Wouldn't "control" be equivalent? Are there any benefits to @this?Bookcraft
@jeromeyers - The @this is simply the variable name, in this case the reference to the current control calling the extension. You could rename it to source, or whatever floats your boat. I use @this, because it's referring to 'this Control' that is calling the extension and is consistent (in my head, at least) with using the 'this' keyword in normal (non-extension) code.Cyrus
This is great, easy and for me the best solution. You could include all the work you have to do in the ui thread. Example: this.UIThread(() => { txtMessage.Text = message; listBox1.Items.Add(message); });Altaf
I really like this solution. Minor nit: I would name this method OnUIThread rather than UIThread.Seascape
@Seascape - The only reason I opted not to use the OnXXX style is because that usually indicates an event overload. OnLoad, OnInitialize, etc. Maybe not the best decision, but it's what I had in mind at the time. And wow, that was almost 6 years ago by now. Time flies.Cyrus
That's why I named this extension RunOnUiThread. But thats just personal taste.Felicific
Why when I add ControlExtensions class FrmMain.Designer.cs throws System.Resources.MissingManifestResourceException: 'Could not find any resources appropriate for the specified culture or the neutral culture. on the following line: this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));Ursa
W
72

This is the classic way you should do this:

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<ProgressChangedArgs>(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<ProgressChangedArgs> 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 string Progress {get;private set;}
        public ProgressChangedArgs(string progress)
        {
            Progress = progress;
        }
    }
}

Your worker thread has an event. Your UI thread starts off another thread to do the work and hooks up that worker event so you can display the state of the worker thread.

Then in the UI you need to cross threads to change the actual control... like a label or a progress bar.

Whaley answered 19/3, 2009 at 10:31 Comment(0)
P
69

The simple solution is to use Control.Invoke.

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

void updateGUI() {
    // update gui here
}
Plenty answered 19/3, 2009 at 9:46 Comment(3)
well done for the simplicity! not only simple, but also works well! I really did not understand why microsoft could not make it simpler as it is meant to be! for calling 1 line on the main thread, we should write couple of functions!Batsman
@Batsman Agree. BTW, did you notice https://mcmap.net/q/17422/-how-do-i-update-the-gui-from-another-thread answer above, which defines an extension method? Do that once in a custom utilities class, then don't have to care any more that Microsoft did not do it for us :)Seascape
@Seascape Thats exactly what it meant to be! you are right we can find a way, but i mean from DRY (don't repeat yourself) point of view, the problem that has common solution, can be solved by them with minimum effort by Microsoft which will save a lot of time for programmers :)Batsman
S
52

The vast majority of answers use Control.Invoke which is a race condition waiting to happen. For example, consider the accepted answer:

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

If the user closes the form just before this.Invoke is called (remember, this is the Form object), an ObjectDisposedException will be likely fired.

The solution is to use SynchronizationContext, specifically SynchronizationContext.Current as hamilton.danielb suggests (other answers rely on specific SynchronizationContext implementations which is completely unnecessary). I would slightly modify his code to use SynchronizationContext.Post rather than SynchronizationContext.Send though (as there's typically no need for the worker thread to wait):

public partial class MyForm : Form
{
    private readonly SynchronizationContext _context;
    public MyForm()
    {
        _context = SynchronizationContext.Current
        ...
    }

    private MethodOnOtherThread()
    {
         ...
         _context.Post(status => someLabel.Text = newText,null);
    }
}

Note that on .NET 4.0 and up you should really be using tasks for async operations. See n-san's answer for the equivalent task-based approach (using TaskScheduler.FromCurrentSynchronizationContext).

Finally, on .NET 4.5 and up you can also use Progress<T> (which basically captures SynchronizationContext.Current upon its creation) as demonstrated by Ryszard Dżegan's for cases where the long-running operation needs to run UI code while still working.

Stamata answered 24/5, 2014 at 8:45 Comment(5)
Since the _context is a variable in Myform if it is disposed wouldn't your solution also fail?Gear
@Gear no because disposing MyForm won't do anything to _context, it will still be SynchronizationContext.Current (which would always be valid as long as the WinForms app is running)Stamata
That is correct, but if MyForm is disposed, wouldn't the someLabel also disposed?Gear
@Gear I believe the assumption here was a vanilla WinForms app where if the form was disposed, it basically means the WinForms app is shutting down, and therefore will not run your delegates on the message loop (otherwise the sync context solution would not have been safe anyway). If your scenario is different, I guess you could add a check like if (someLabel.IsDisposed) { someLabel.Text = newText } (safe because at that point you are running on the UI thread, specifically blocking the message pump from disposing the label).Stamata
Correct, I have an app that 1 in 10k run drops an exception log that component is disposed and is not accessible (or a message like that), in any case IsDisposed should be checked if someone doesn't need that one in 10,000 message in their log, specially when your boss freaks out seeing an exception in logs!Gear
M
51

Threading code is often buggy and always hard to test. You don't need to write threading code to update the user interface from a background task. Just use the BackgroundWorker class to run the task and its ReportProgress method to update the user interface. Usually, you just report a percentage complete, but there's another overload that includes a state object. Here's an example that just reports a string object:

    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.ToString();
    }

That's fine if you always want to update the same field. If you've got more complicated updates to make, you could define a class to represent the UI state and pass it to the ReportProgress method.

One final thing, be sure to set the WorkerReportsProgress flag, or the ReportProgress method will be completely ignored.

Manteau answered 27/8, 2010 at 20:42 Comment(1)
At the end of processing, it is also possible to update the user interface via backgroundWorker1_RunWorkerCompleted.Agog
T
43

You'll have to make sure that the update happens on the correct thread; the UI thread.

In order to do this, you'll have to Invoke the event-handler instead of calling it directly.

You can do this by raising your event like this:

(The code is typed here out of my head, so I haven't checked for correct syntax, etc., but it should get you going.)

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 ( ... );
      }
   }
}

Note that the code above will not work on WPF projects, since WPF controls do not implement the ISynchronizeInvoke interface.

In order to make sure that the code above works with Windows Forms and WPF, and all other platforms, you can have a look at the AsyncOperation, AsyncOperationManager and SynchronizationContext classes.

In order to easily raise events this way, I've created an extension method, which allows me to simplify raising an event by just calling:

MyEvent.Raise(this, EventArgs.Empty);

Of course, you can also make use of the BackGroundWorker class, which will abstract this matter for you.

Themistocles answered 19/3, 2009 at 9:45 Comment(3)
Indeed, but I don't like to 'clutter' my GUI code with this matter. My GUI shouldn't care whether it needs to Invoke or not. In other words: i don't think that it is the responsability of the GUI to perform the context-swithc.Themistocles
Breaking the delegate apart etc seems overkill - why not just: SynchronizationContext.Current.Send(delegate { MyEvent(...); }, null);Bashuk
Do you always have access to the SynchronizationContext ? Even if your class is in a class lib ?Themistocles
A
34

Because of the triviality of the scenario I would actually have the UI thread poll for the status. I think you will find that it can be quite elegant.

public class MyForm : Form
{
  private volatile string 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...";
    }
  }
}

The approach avoids the marshaling operation required when using the ISynchronizeInvoke.Invoke and ISynchronizeInvoke.BeginInvoke methods. There is nothing wrong with using the marshaling technique, but there are a couple of caveats you need to be aware of.

  • Make sure you do not call BeginInvoke too frequently or it could overrun the message pump.
  • Calling Invoke on the worker thread is a blocking call. It will temporarily halt the work being done in that thread.

The strategy I propose in this answer reverses the communication roles of the threads. Instead of the worker thread pushing the data the UI thread polls for it. This a common pattern used in many scenarios. Since all you are wanting to do is display progress information from the worker thread then I think you will find that this solution is a great alternative to the marshaling solution. It has the following advantages.

  • The UI and worker threads remain loosely coupled as opposed to the Control.Invoke or Control.BeginInvoke approach which tightly couples them.
  • The UI thread will not impede the progress of the worker thread.
  • The worker thread cannot dominate the time the UI thread spends updating.
  • The intervals at which the UI and worker threads perform operations can remain independent.
  • The worker thread cannot overrun the UI thread's message pump.
  • The UI thread gets to dictate when and how often the UI gets updated.
Algonkian answered 19/3, 2009 at 9:37 Comment(3)
Good idea. The only thing you didn't mention is how you properly dispose the timer once the WorkerThread is finished. Note this can cause trouble when the application ends (i.e. the user closes the application). Do you have an idea how to solve this?Graver
@Graver Instead of using an anonymous handler for Elapsed event, you use a member method so you can remove the timer when the form is disposed...Muntjac
@Muntjac - Good point. You meant like System.Timers.ElapsedEventHandler handler = (s, a) => { MyProgressLabel.Text = m_Text; }; and assigning it via m_Timer.Elapsed += handler;, later in the dispose context doing a m_Timer.Elapsed -= handler; am I right? And for the disposing/closing following the advice as discussed here.Graver
F
32

You'll need to Invoke the method on the GUI thread. You can do that by calling Control.Invoke.

For example:

delegate void UpdateLabelDelegate (string message);

void UpdateLabel (string message)
{
    if (InvokeRequired)
    {
         Invoke (new UpdateLabelDelegate (UpdateLabel), message);
         return;
    }

    MyLabelControl.Text = message;
}
Frankfurter answered 19/3, 2009 at 9:47 Comment(1)
The invoke line gives me a compiler error. The best overloaded method match for 'System.Windows.Forms.Control.Invoke(System.Delegate, object[])' has some invalid argumentsFloriated
M
30

None of the Invoke stuff in the previous answers is necessary.

You need to look at 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
}
Maitland answered 31/5, 2013 at 11:12 Comment(1)
what do you think the Post method uses under the hood? :)Mettle
S
26

This one is similar to the solution above using .NET Framework 3.0, but it solved the issue of compile-time safety support.

public  static class ControlExtension
{
    delegate void SetPropertyValueHandler<TResult>(Control souce, Expression<Func<Control, TResult>> selector, TResult value);

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

To use:

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

The compiler will fail if the user passes the wrong data type.

this.lblTimeDisplay.SetPropertyValue(a => a.Visible, "sometext");
Shantung answered 2/3, 2011 at 6:59 Comment(0)
M
26

Salvete! Having searched for this question, I found the answers by FrankG and Oregon Ghost to be the easiest most useful to me. Now, I code in Visual Basic and ran this snippet through a convertor; so I'm not sure quite how it turns out.

I have a dialog form called form_Diagnostics, which has a richtext box, called updateDiagWindow, which I am using as a sort of logging display. I needed to be able to update its text from all threads. The extra lines allow the window to automatically scroll to the newest lines.

And so, I can now update the display with one line, from anywhere in the entire program in the manner which you think it would work without any threading:

  form_Diagnostics.updateDiagWindow(whatmessage);

Main Code (put this inside of your form's class code):

#region "---------Update Diag Window Text------------------------------------"
// This sub allows the diag window to be updated by all threads
public void updateDiagWindow(string 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(string whatmessage);
private void UpdateDiag(string whatmessage)
{
    var _with2 = diagwindow;
    _with2.appendtext(whatmessage);
    _with2.SelectionStart = _with2.Text.Length;
    _with2.ScrollToCaret();
}
#endregion
Midden answered 17/12, 2011 at 19:51 Comment(0)
S
23
Label lblText; //initialized elsewhere

void AssignLabel(string text)
{
   if (InvokeRequired)
   {
      BeginInvoke((Action<string>)AssignLabel, text);
      return;
   }

   lblText.Text = text;           
}

Note that BeginInvoke() is preferred over Invoke() because it's less likely to cause deadlocks (however, this is not an issue here when just assigning text to a label):

When using Invoke() you are waiting for the method to return. Now, it may be that you do something in the invoked code that will need to wait for the thread, which may not be immediately obvious if it's buried in some functions that you are calling, which itself may happen indirectly via event handlers. So you would be waiting for the thread, the thread would be waiting for you and you are deadlocked.

This actually caused some of our released software to hang. It was easy enough to fix by replacing Invoke() with BeginInvoke(). Unless you have a need for synchronous operation, which may be the case if you need a return value, use BeginInvoke().

Scenography answered 28/5, 2012 at 0:23 Comment(0)
G
22

For many purposes it's as simple as this:

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

"serviceGUI()" is a GUI level method within the form (this) that can change as many controls as you want. Call "updateGUI()" from the other thread. Parameters can be added to pass values, or (probably faster) use class scope variables with locks on them as required if there is any possibility of a clash between threads accessing them that could cause instability. Use BeginInvoke instead of Invoke if the non-GUI thread is time critical (keeping Brian Gideon's warning in mind).

Gadgeteer answered 23/8, 2010 at 23:13 Comment(0)
G
22

When I encountered the same issue I sought help from Google, but rather than give me a simple solution it confused me more by giving examples of MethodInvoker and blah blah blah. So I decided to solve it on my own. Here is my solution:

Make a delegate like this:

Public delegate void LabelDelegate(string s);

void Updatelabel(string 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.

Grapeshot answered 24/10, 2012 at 6:38 Comment(0)
S
21

This in my C# 3.0 variation of Ian Kemp's solution:

public static void SetPropertyInGuiThread<C,V>(this C control, Expression<Func<C, V>> 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<C, Expression<Func<C, V>>, V>)SetPropertyInGuiThread,
            new object[] { control, property, value }
        );
    else
        propertyInfo.SetValue(control, value, null);
}

You call it like this:

myButton.SetPropertyInGuiThread(b => b.Text, "Click Me!")
  1. It adds null-checking to the result of the "as MemberExpression".
  2. It improves the static type-safety.

Otherwise, the original is a very nice solution.

Somewhere answered 15/9, 2011 at 20:40 Comment(0)
S
19

Most of the other answers are a little complex for me on this question (I'm new to C#), so I am writing mine:

I have a WPF application and have defined a worker as below:

Issue:

BackgroundWorker workerAllocator;
workerAllocator.DoWork += delegate (object sender1, DoWorkEventArgs e1) {
    // This is my DoWork function.
    // It is given as an anonymous function, instead of a separate DoWork function

    // I need to update a message to textbox (txtLog) from this thread function

    // Want to write below line, to update UI
    txt.Text = "my message"

    // But it fails with:
    //  'System.InvalidOperationException':
    //  "The calling thread cannot access this object because a different thread owns it"
}

Solution:

workerAllocator.DoWork += delegate (object sender1, DoWorkEventArgs e1)
{
    // The below single line works
    txtLog.Dispatcher.BeginInvoke((Action)(() => txtLog.Text = "my message"));
}

I am yet to find out what the above line means, but it works.

For WinForms:

Solution:

txtLog.Invoke((MethodInvoker)delegate
{
    txtLog.Text = "my message";
});
Spirituel answered 17/11, 2016 at 23:26 Comment(4)
The question was about Winforms, not WPF.Scholasticate
Thanks. Added WinForms solution above.Spirituel
...which is just a copy of however many other answers on this same question, but okay. Why not be part of the solution and just delete your answer?Scholasticate
hmm, correct you are, if only, you read my answer with attention, the beginning part (the reason why i wrote the answer), and hopefully with a little more attention you see there is someone who had exact same problem & upvoted today for my simple answer, and with even more attn if you could foresee the real story on why all this happened, that google sends me here even when i search for wpf. Sure since you missed these more or less obvious 3 reasons, i can understand why you won't remove your downvote. Instead of cleaning the okay one, create something new which is much more difficult.Spirituel
T
18

Simply use something like this:

 this.Invoke((MethodInvoker)delegate
            {
                progressBar1.Value = e.ProgressPercentage; // runs on UI thread
            });
Tincal answered 11/1, 2016 at 19:47 Comment(2)
If you have e.ProgressPercentage, aren't you already in the UI thread from the method you are calling this?Pearcy
The ProgressChanged event runs on the UI thread. That's one of the conveniences of using the BackgroundWorker. The Completed event runs on the gui, too. The only thing running in the non-UI thread is the DoWork method.Pearcy
C
16

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, string text)
    {
        if (InvokeRequired) { Invoke(new Action<int, string>(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".

Curry answered 22/2, 2012 at 13:1 Comment(0)
B
16

You may use the already-existing delegate Action:

private void UpdateMethod()
{
    if (InvokeRequired)
    {
        Invoke(new Action(UpdateMethod));
    }
}
Bali answered 27/7, 2012 at 23:8 Comment(0)
J
16

And yet another generic Control extension aproach..

First add an extension method for objects of type Control

public static void InvokeIfRequired<T>(this T c, Action<T> action) where T : Control
{
    if (c.InvokeRequired)
    {
        c.Invoke(new Action(() => action(c)));
    }
    else
    {
        action(c);
    }
}

and call like this from another thread to access a Control named object1 in UI-thread:

object1.InvokeIfRequired(c => { c.Visible = true; });
object1.InvokeIfRequired(c => { c.Text = "ABC"; });

..or like this

object1.InvokeIfRequired(c => 
  { 
      c.Text = "ABC";
      c.Visible = true; 
  }
);
Jerid answered 17/11, 2018 at 21:40 Comment(2)
Very elegant, very nice!Ryder
I have started using c.BeginInvoke for asynchronous update. It is less likely to cause deadlocks if Invoked in a cascade.Jerid
H
15

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);
Hot answered 19/2, 2014 at 17:36 Comment(0)
O
13

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);
    }
}
Orella answered 17/6, 2013 at 7:6 Comment(1)
Is it for Windows Forms ?Verse
A
13

You must use invoke and delegate

private delegate void MyLabelDelegate();
label1.Invoke( new MyLabelDelegate(){ label1.Text += 1; });
Aitch answered 10/9, 2013 at 13:55 Comment(0)
R
12

The simplest way in WPF applications is:

this.Dispatcher.Invoke((Action)(() =>
{
    // This refers to a form in a WPF application 
    val1 = textBox.Text; // Access the UI 
}));
Reichel answered 27/6, 2016 at 11:31 Comment(2)
This is correct, if you are using a WPF application. But he is using Windows Forms.Spun
You can use the Dispatcher even in a Winforms application. stackoverflow.com/questions/303116/…Shantung
M
10

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<string>(LengthyComputation);
    task.ContinueWith(antecedent =>
                         UpdateResultLabel(antecedent.Result), _uiTaskScheduler);
    task.Start();
  }

  private string LengthyComputation()
  {
    Thread.Sleep(3000);
    return "47";
  }

  private void UpdateResultLabel(string text)
  {
    labelResult.Text = text;
  }
}

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

Meridional answered 11/5, 2014 at 18:43 Comment(1)
Calling Task.Start is typically not a good practice blogs.msdn.com/b/pfxteam/archive/2012/01/14/10256832.aspxStamata
L
9

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

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

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

Ln answered 19/3, 2014 at 6:27 Comment(0)
H
9

Even if the operation is time-consuming (thread.sleep in my example) - This code will NOT lock your UI:

 private void button1_Click(object sender, EventArgs e)
 {

      Thread t = new Thread(new ThreadStart(ThreadJob));
      t.IsBackground = true;
      t.Start();         
 }

 private void ThreadJob()
 {
     string newValue= "Hi";
     Thread.Sleep(2000); 

     this.Invoke((MethodInvoker)delegate
     {
         label1.Text = newValue; 
     });
 }
Hern answered 31/10, 2015 at 16:51 Comment(0)
E
8

The easiest way I think:

   void Update()
   {
       BeginInvoke((Action)delegate()
       {
           //do your update
       });
   }
Extravagancy answered 18/2, 2014 at 4:41 Comment(0)
H
8

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(string 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).

Houseboat answered 6/11, 2014 at 15:39 Comment(3)
Came here to find this, as I also check for IsHandleCreated. One other property to check is IsDisposed. If your form is disposed, you cannot call Invoke() on it. If the user closed the form before your background thread could complete you don't want it trying to call back to the UI when the form is disposed.Cherin
I would say that it is a bad idea to start with... Normally, you would show the child form immediately and have a progress bar or some other feedback while doing background processing. Or you would do all processing first and then pass the result to the new form at creation. Doing both at the same time would generally have marginal benefits but much less maintainable code.Muntjac
The described scenario takes into account a modal form used as a progress view of a background-thread job. Because it must be modal, it must be shown by calling the Form.ShowDialog() method. By doing this, you prevent your code that follows the call to be executed until the form is closed. So, unless you can start the background thread differently from the given example (and, of course, you can) this form must be modally shown after the background thread has started. In this case, you need to check for the Handle to be created. If you don't need a modal form, then it's another story.Houseboat
C
8

just use synchronization context of ui

using System.Threading;

// ...

public partial class MyForm : Form
{
    private readonly SynchronizationContext uiContext;

    public MyForm()
    {
        InitializeComponent();
        uiContext = SynchronizationContext.Current; // get ui thread context
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Thread t = new Thread(() =>
            {// set ui thread context to new thread context                            
             // for operations with ui elements to be performed in proper thread
             SynchronizationContext
                 .SetSynchronizationContext(uiContext);
             label1.Text = "some text";
            });
        t.Start();
    }
}
Consensus answered 11/4, 2019 at 13:17 Comment(2)
Sure thing. I've added comments for that purpose.Consensus
This is the most straightforward and readable method IMO.Adapa
B
7

I couldn't get Microsoft's logic behind this ugly implementation, but you have to have two functions:

void setEnableLoginButton()
{
  if (InvokeRequired)
  {
    // btn_login can be any conroller, (label, button textbox ..etc.)

    btn_login.Invoke(new MethodInvoker(setEnable));

    // OR
    //Invoke(new MethodInvoker(setEnable));
  }
  else {
    setEnable();
  }
}

void setEnable()
{
  btn_login.Enabled = isLoginBtnEnabled;
}

These snippets work for me, so I can do something on another thread, and then I update the GUI:

Task.Factory.StartNew(()=>
{
    // THIS IS NOT GUI
    Thread.Sleep(5000);
    // HERE IS INVOKING GUI
    btn_login.Invoke(new Action(() => DoSomethingOnGUI()));
});

private void DoSomethingOnGUI()
{
   // GUI
   MessageBox.Show("message", "title", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}

Even simpler:

btn_login.Invoke(new Action(()=>{ /* HERE YOU ARE ON GUI */ }));
Batsman answered 19/12, 2015 at 9:27 Comment(0)
D
6

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 (e.g. before the form is shown), Invoke throws an exception. So I recommend always checking on InvokeRequired before calling Invoke or BeginInvoke.

Dysgraphia answered 6/2, 2014 at 9:46 Comment(0)
C
6

Maybe a little bit overdose, but this is the kind of way I solve this normally:

Invokes are not required here because of the synchronization. The BasicClassThreadExample is just a kind of layout for me, so change it to fit your actual needs.

It is simple because you don't need to handle the stuff in the UI thread!

public partial class Form1 : Form
{
    BasicClassThreadExample _example;

    public Form1()
    {
        InitializeComponent();
        _example = new BasicClassThreadExample();
        _example.MessageReceivedEvent += _example_MessageReceivedEvent;
    }

    void _example_MessageReceivedEvent(string command)
    {
        listBox1.Items.Add(command);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        listBox1.Items.Clear();
        _example.Start();
    }
}

public class BasicClassThreadExample : IDisposable
{
    public delegate void MessageReceivedHandler(string msg);

    public event MessageReceivedHandler MessageReceivedEvent;

    protected virtual void OnMessageReceivedEvent(string msg)
    {
        MessageReceivedHandler handler = MessageReceivedEvent;
        if (handler != null)
        {
            handler(msg);
        }
    }

    private System.Threading.SynchronizationContext _SynchronizationContext;
    private System.Threading.Thread _doWorkThread;
    private bool disposed = false;

    public BasicClassThreadExample()
    {
        _SynchronizationContext = System.ComponentModel.AsyncOperationManager.SynchronizationContext;
    }

    public void Start()
    {
        _doWorkThread = _doWorkThread ?? new System.Threading.Thread(dowork);

        if (!(_doWorkThread.IsAlive))
        {
            _doWorkThread = new System.Threading.Thread(dowork);
            _doWorkThread.IsBackground = true;
            _doWorkThread.Start();
        }
    }

    public void dowork()
    {
        string[] retval = System.IO.Directory.GetFiles(@"C:\Windows\System32", "*.*", System.IO.SearchOption.TopDirectoryOnly);
        foreach (var item in retval)
        {
            System.Threading.Thread.Sleep(25);
            _SynchronizationContext.Post(new System.Threading.SendOrPostCallback(delegate(object obj)
            {
                OnMessageReceivedEvent(item);
            }), null);
        }
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                _doWorkThread.Abort();
            }
            disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~BasicClassThreadExample() { Dispose(false); }

}
Cornu answered 1/5, 2014 at 11:29 Comment(0)
K
6

Basically the way to resolve this issue regardless of the framework version or the GUI underlying library type is to save the control creating the thread's Synchronization context for the worker thread that will marshal the control's related interaction from the worker thread to the GUI's thread messages queue.

Example:

SynchronizationContext ctx = SynchronizationContext.Current; // From control
ctx.Send\Post... // From worker thread
Karns answered 31/1, 2015 at 13:33 Comment(0)
B
6

Here's a new look on an age-old issue using a more functional style. If you keep the TaskXM class in all of your projects you only have one line of code to never worry about cross-thread updates again.

public class Example
{
    /// <summary>
    /// No more delegates, background workers, etc. Just one line of code as shown below.
    /// Note it is dependent on the Task Extension method shown next.
    /// </summary>
    public async void Method1()
    {
        // Still on the GUI thread here if the method was called from the GUI thread
        // This code below calls the extension method which spins up a new task and calls back.
        await TaskXM.RunCodeAsync(() =>
        {
            // Running an asynchronous task here
            // Cannot update the GUI thread here, but can do lots of work
        });
        // Can update GUI on this line
    }
}


/// <summary>
/// A class containing extension methods for the Task class
/// </summary>
public static class TaskXM
{
    /// <summary>
    /// RunCodeAsyc is an extension method that encapsulates the Task.run using a callback
    /// </summary>
    /// <param name="Code">The caller is called back on the new Task (on a different thread)</param>
    /// <returns></returns>
    public async static Task RunCodeAsync(Action Code)
    {
        await Task.Run(() =>
        {
            Code();
        });
        return;
    }
}
Burp answered 16/5, 2016 at 1:50 Comment(2)
Really asking: how does wrapping Task.Run like this differ from just calling await Task.Run(() => {...});? What is the advantage of the indirection here?Scholasticate
Superficially no difference. Looking deeper, it shows the power of functional programming. In particular it is wrapping a static method which aids in single responsibility. What if you now wanted to implement ConfigureAwait(false) or add a logging statement. You can now do it just once.Burp
E
6

Another example about the subject: I made an abstract class, UiSynchronizeModel, that contains a common method implementation:

public abstract class UiSynchronizeModel
{
    private readonly TaskScheduler uiSyncContext;
    private readonly SynchronizationContext winformsOrDefaultContext;

    protected UiSynchronizeModel()
    {
        this.winformsOrDefaultContext = SynchronizationContext.Current ?? new SynchronizationContext();
        this.uiSyncContext = TaskScheduler.FromCurrentSynchronizationContext();
    }

    protected void RunOnGuiThread(Action action)
    {
        this.winformsOrDefaultContext.Post(o => action(), null);
    }

    protected void CompleteTask(Task task, TaskContinuationOptions options, Action<Task> action)
    {
        task.ContinueWith(delegate
        {
            action(task);
            task.Dispose();
        }, CancellationToken.None, options, this.uiSyncContext);
    }
}

Your model or controller class should be derived from this abstract class. You can use any pattern (tasks or manually managed background threads) and use these methods like this:

public void MethodThatCalledFromBackroundThread()
{
   this.RunOnGuiThread(() => {
       // Do something over UI controls
   });
}

Tasks example:

var task = Task.Factory.StartNew(delegate
{
    // Background code
    this.RunOnGuiThread(() => {
        // Do something over UI controls
    });
});

this.CompleteTask(task, TaskContinuationOptions.OnlyOnRanToCompletion, delegate
{
    // Code that can safely use UI controls
});
Elysha answered 5/3, 2017 at 7:42 Comment(0)
L
5

First get the instance of your form (in this case mainForm), and then just use this code in the another thread.

mainForm.Invoke(new MethodInvoker(delegate () 
{
    // Update things in my mainForm here
    mainForm.UpdateView();
}));
Lakh answered 18/1, 2017 at 13:1 Comment(0)
D
4

Put some common variable in a separate class to hold the value.

Example:

public  class data_holder_for_controls
{
    // It will hold the value for your label
    public string status = string.Empty;
}

class Demo
{
    public static  data_holder_for_controls d1 = new data_holder_for_controls();

    static void Main(string[] args)
    {
        ThreadStart ts = new ThreadStart(perform_logic);
        Thread t1 = new Thread(ts);
        t1.Start();
        t1.Join();
        //your_label.Text=d1.status; --- can access it from any thread
    }

    public static void perform_logic()
    {
        // Put some code here in this function
        for (int i = 0; i < 10; i++)
        {
            // Statements here
        }
        // Set the result in the status variable
        d1.status = "Task done";
    }
}
Digression answered 25/3, 2017 at 4:40 Comment(0)
O
3

I prefer this one:

private void UpdateNowProcessing(string nowProcessing)
{
    if (this.InvokeRequired)
    {
        Action<string> d = UpdateNowProcessing;
        Invoke(d, nowProcessing);
    }
    else
    {
        this.progressDialog.Next(nowProcessing);
    }            
}
Oxide answered 27/1, 2014 at 13:39 Comment(0)
D
3

General approach is like:

using System;
using System.Threading;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        int clickCount = 0;

        public Form1()
        {
            InitializeComponent();
            label1.SetText("0");
        }

        private void button1_Click(object sender, EventArgs e)
        {
            new Thread(() => label1.SetText((++clickCount).ToString())).Start();
        }
    }

    public static class ControlExtensions
    {
        public static void SetText(this Control control, string text)
        {
            if (control.InvokeRequired)
                control.Invoke(setText, control, text);
            else
                control.Text = text;
        }

        private static readonly Action<Control, string> setText =
            (control, text) => control.Text = text;
    }
}

Explanation:

The answer is pretty like this one. But uses neater (as for me) and newer syntax. The point is InvokeRequired property of control. It gets a value indicating whether the caller must call an invoke method when making method calls to the control because the caller is on a different thread than the one the control was created on. So if we call control.SetText("some text") on the same thread control was created on, it's OK just to set Text as this control.Text = text. But on any other thread it causes System.InvalidOperationException so one must call a method via control.Invoke(...) to set Text on the thread control was created on.

Driftage answered 11/4, 2019 at 12:0 Comment(0)
C
2

In my case (WPF) the solution is simple as this:

private void updateUI()
{
    if (!Dispatcher.CheckAccess())
    {
        Dispatcher.BeginInvoke(updateUI);
        return;
    }

    // Update any number of controls here
}
Citrin answered 8/8, 2015 at 7:49 Comment(1)
Question is for Winforms.Scholasticate
E
0

To achieve this in WPF I do it the following way.

 new Thread(() => 
 {
     while (...)
     {
         SomeLabel.Dispatcher.BeginInvoke((Action)(() => SomeLabel.Text = ...));
     }
 }).Start();
Erichericha answered 2/7, 2014 at 7:28 Comment(1)
The question is actually about [winforms], by the way.Leftist
B
0

Simplest way is invoking as follows:

 Application.Current.Dispatcher.Invoke(new Action(() =>
             {
                    try
                    {
                        ///
                    }
                    catch (Exception)
                    {
                      //
                    }


                    }
     ));
Bicknell answered 28/2, 2018 at 10:22 Comment(2)
Except that the question is for WinForms.Pearcy
Don't know why this was downvoted!? it help me with my issue in a WPF application. Not all readers of this post will have exactly same issue as OP, sometimes a part of the solution can help the reader in a shorter time, then a complete solution to a unique problem.Electrodynamic

© 2022 - 2024 — McMap. All rights reserved.