Share via


How can I update my user interface from a thread that did not create it?

When performing any action on a control which requires the updating of a user interface element (e.g. setting the Text property on almost any class derived from Control, updating the data source behind a DataGrid), these operations MUST take place on the thread that created the UI element.

In order to do this, the Control class provides the Invoke method, which will take a delegate and execute it on the thread that the UI element was created on. In order to use this, one must declare a function that performs the UI operation. For example, say a form has a TextBox on it named m_TextBox. To update the text from another thread, create a method that will update the Text property on the TextBox:

 
 // The declaration of the textbox.
private TextBox m_TextBox;

// Updates the textbox text.
private void UpdateText(string text)
{
  // Set the textbox text.
  m_TextBox.Text = text;
}

Now, create a delegate that has the same signature as the method that was previously defined:

 public delegate void UpdateTextCallback(string text);

In your thread, you can call the Invoke method on m_TextBox, passing the delegate to call, as well as the parameters.

 m_TextBox.Invoke(new UpdateTextCallback(this.UpdateText), 
            new object[]{”Text generated on non-UI thread.”});

Note: Do not create a method that matches the EventHandler delegate signature and pass that. The implementation of Invoke on the Control class will not take into account the parameters passed to Invoke if the type of the delegate is EventHandler. It will pass the control that Invoke was called on for the sender parameter as well as the value returned by EventArgs.Empty for the e parameter.

[Author: Nicholas Paldino]

Comments

  • Anonymous
    March 17, 2004
    Hi Nicholas,
    Yes, I've done this before, and it's a pain in the rear. I come from C++, and love C# since (among other things) it saves me time updating headers. However, 3 things that I hate about C# are the typing associted with updating of controls in threads that you outline, the typing to have "generic" get/set calls for a class variable (why not an attribute?), and the lack of default params in function calls (come on, even VB has this). Please, guys, you built a beautiful language - now help me cut down on all the typing that I have to do.

    Ed Eichman
    Cambrils, Spain

  • Anonymous
    March 17, 2004
    The comment has been removed

  • Anonymous
    March 17, 2004
    Actually, i pre-empted you would ask how i connect 200+ IP's inside same second. Actually i didn't. I tried this against lan ip's and when the OnRemoteConnected tries BeginReceive and fails, it calls Update("connection failed"); .. obviously!

  • Anonymous
    March 18, 2004
    The comment has been removed

  • Anonymous
    March 18, 2004
    Ed, it's not C#'s problem, not even .NET's, that you cannot access controls from another thread than that which created the control. You have to do it as well when programming with C++ against the Win32 API.
    Secondly, what should be attributed for getters/setters? The class variable? That would negate the advantage of them.

  • Anonymous
    March 31, 2004
    The problem that I'm having is that the call to ListView.Invoke() itself deadlocks. I have no idea why this would be happening. Here is what I do:

    1) Create a ListView control
    2) Call an Asynchronous Delegate from the UI thread
    3) Call ListView.Invoke from the Asynchronous Delegate to call another delegate

    The result is that ListView.Invoke deadlocks, with the top of the call stack for that thread showing "System.Threading.WaitHandle.WaitOne()" In fact, calling ListView.Refresh() or just about anything else will cause a deadlock as well. As far as I can tell, no other thread is using the ListView. What could be causing this?

  • Anonymous
    April 27, 2004
    how also we call a function from a user interface when the function is writen in c++ and the GUI in c#.

  • Anonymous
    May 24, 2004
    I am trying to do this from another class altogether, not just another thread of the same class. How would I do this? Do I still have to pass the reference of the form to the other class inorder for it to be able to update my form when the right event occurs?

    Thanks
    Abdullah

  • Anonymous
    July 01, 2004
    Please, clearly explain to me about the way to create the user-interface thread(step-by-step).

    Thanks

  • Anonymous
    July 01, 2004
    Please, clearly explain to me about the way to create the user-interface thread(step-by-step).

    Thanks

  • Anonymous
    July 22, 2004
    Hi, I have tried to use the above method but got a run time error : arguementexception when it tries to invoke the datagrid..any idea what happened?

    have a delegate method(UpdateTextCallback) to update the
    datagrid(updateDs2)

    updateDs2 (DataSet ds)
    {
    datagrid2.datasource = ds.tables[0].defaultview;
    }

    private void viewAttendanceNotes_dsStatus(DataSet myDs_viewAttNotes)
    {
    this.viewNoteProgressBar.Value=100;
    this.viewNoteProgressBar.Hide();
    Cursor.Current = Cursors.Default;
    //new code - not so sure about the syntax. Somehow i need to pass the
    dataset into the updateDs2 para
    this.dataGrid2.Invoke(new UpdateTextCallback(this.updateDs2));
    }

  • Anonymous
    July 28, 2004
    The comment has been removed

  • Anonymous
    September 08, 2007
    PingBack from http://mikesdump.wordpress.com/2006/01/15/net-compact-framework-updating-the-user-interface-from-a-worker-thread/

  • Anonymous
    December 18, 2008
    PingBack from http://www.innobead.com/davidko/?p=55

  • Anonymous
    January 21, 2009
    PingBack from http://www.keyongtech.com/433106-best-way-to-design-multithreading

  • Anonymous
    January 24, 2009
    PingBack from http://vdplaat.dnsalias.com/wp/?p=602

  • Anonymous
    November 21, 2009
    Thank you, you made a student coding his AI assignment, very happy. Phew!!

  • Anonymous
    November 25, 2009
    This is great, if only the Invoke method existed on WPF controls! Is there a similar way to accomplish this in a WPF application?

  • Anonymous
    December 01, 2009
    Thanks. I was looking for just this.

  • Anonymous
    December 16, 2009
    If the UI controls already support an Invoke method, and there is a property called InvokeRequied, then why is it that the controls do not check the InvokeRequired and call the Invoke method all internally?

  • Anonymous
    January 26, 2010
    thanks man, I finally get what the delegate is about :)

  • Anonymous
    February 11, 2010
    All you need to talk to your UI is an object ref to your UI object right? I got it by : // in your background thread, put this code string stringFilledOnDifferentThread = "New Info"; // get your UI to write it to Form aForm = Application.OpenForms["Form1"]; // cast it to your form YourApplicationNameHere.Form1 myForm = (YourApplicationNameHere)aForm; // now you can get your UI control System.Windows.Forms.Control myLabel = myForm.Controls["CostPerMile"]; // update it from your thread myLabel.Text = stringFilledOnDifferentThread;

  • Anonymous
    February 11, 2010
    OOPS! typo... YourApplicationNameHere.Form1 myForm = (YourApplicationNameHere)aForm; the cast should have been this: YourApplicationNameHere.Form1 myForm = (YourApplicationNameHere.Form1)aForm;

  • Anonymous
    February 18, 2010
    I miss C++ and Qt4's Data Models

  • Anonymous
    March 15, 2010
    Hello, Thank you for the article, it is helpful. However, what happens when you need to do more complicated updates on the object? For example, if I have a listview object, I would like to make the call: listview1.Columns.Add("TestCol", -2, HorizontalAlignment.Left) But the example code above is only really made for the simple calls of: textbox1.Name = "my new textbox" Any help would be appreciated, thanks.

  • Anonymous
    March 18, 2010
    Check it out: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; namespace GuiThreading {    public partial class MainForm : Form    {        public MainForm()        {            InitializeComponent();        }        private void MainForm_Load(object sender, EventArgs e)        {        }        private void DoWorkButton_Click(object sender, EventArgs e)        {            Thread workerThread = new Thread(new ThreadStart(DoSomeWork));            workerThread.Start();        }        private void DoSomeWork()        {            for (int i = 0; i < 100; i++)            {                Thread.Sleep(10);                this.Invoke((ThreadStart)delegate()                {                    workResults.Text += i.ToString() + " ";                });            }        }    } }

  • Anonymous
    April 26, 2010
    The comment has been removed

  • Anonymous
    May 24, 2010
    Thanks for a very informative and simple article.

  • Anonymous
    September 05, 2011
    Always needed to read tons of boring pages about delegates, and now you come with this article... Wonderful, immediate, simple. You really made me understand in less than 1 minute what I hardly tried to do after hours. That's it !!! Thank you !!!!!!!!!!!!!!!!!

  • Anonymous
    November 15, 2011
    I had this issue for a while and found a simple way to switch between worker thread and UI thread in a SINGLE method (also multiple times) using a helper class. I.e. no delegates, no callbacks. It can be found together with some example code at asyncexecutor.codeplex.com

  • Anonymous
    December 14, 2011
    Hi All, I have a requirement to add status bar to a UI tool and update status bar with different messages but, there messages will be passed from different places and from different classes. Example if a user performs a Save Action on the tool ,  when there is a backened call going on for save, status bar should get update that 'Backend call processing', after backend call . it should get updated that, 'Backend call succfully done'etc.. how can i achieve this.

  • Anonymous
    February 05, 2012
    The comment has been removed

  • Anonymous
    November 03, 2013
    Hi Nicholas, I have been trying to this from past 2 days going through so many blogs and tutorials. You have explained it in very simplest possible way. Its superb article on cross thread working. Thanks man... great job. Regards,