C# Frequently Asked Questions

The C# team posts answers to common questions

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]

Published Wednesday, March 17, 2004 8:58 PM by CSharpFAQ
Filed under:

Comments

 

Ed Eichman said:

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
March 18, 2004 12:47 AM
 

Steve Noobs said:

I really can't say how many days i spent researching the threading topic, as i'm new to it. I actually never did the control updating without Invoke, but it seemed there was problems anyway, so question did i do 'right' when i chose to do this:

worker class:
some method calls: Update("blabla");

public void Update(string str)
{
UpdateControl uc= new UpdateControl(controlclass.Update);
uc.DynamicInvoke(new object[]{ (stopwatch.Peek() / (float)10).ToString() + str });
}

delegate void UpdateControl(string str);



control class:
public void Update(string s)
{
AppendTextDelegate atd = new AppendTextDelegate(MyAppendText);
textBox1.BeginInvoke(atd,new object[]{s.Trim() + Environment.NewLine});
}


public void MyAppendText(string str)
{
lock(textBox1)
{
textBox1.AppendText(str);
}
}

--
Situation is i have the Update method of the worker class called from various places in that class, updating the stopwatch time elapsed (QueryPerformanceCounter) into the controls texbox. The test cases i encountered some problems initially was when i did this in worker class some 200 times
socket.BeginConnect(ipep,new AsyncCallback(this.OnRemoteConnected),this);

OnRemoteConnected calls the Update. There was some incorrectly updated line in the textbox, so i ended putting up all this lock etc crap you see pasted here. I doubt this should be really necessary, whats your take on this?

March 18, 2004 4:58 AM
 

Steve Noobs said:

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!
March 18, 2004 5:19 AM
 

Kevin Moore said:

Here is some boiler plate that I use a lot. The benefit is that the delegate stays with the target function and their is only one function for both the external caller and the internal implementation.

public delegate string function(object[] params);

public string foo(object[] parameters)
{
if(InvokeRequired)
{
Debug.WriteLine("not in the right thread");
return (string)Invoke(new function(foo),parameters);
}
else
{
return "cool, huh?";
}
}
March 18, 2004 2:36 PM
 

Thomas Freudenberg said:

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.
March 19, 2004 4:14 AM
 

Mike V said:

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?
March 31, 2004 3:37 PM
 

reem said:

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

Abdullah said:

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
May 24, 2004 8:31 AM
 

Nguyen Thanh Tien said:

Please, clearly explain to me about the way to create the user-interface thread(step-by-step).

Thanks
July 2, 2004 12:18 AM
 

Nguyen Thanh Tien said:

Please, clearly explain to me about the way to create the user-interface thread(step-by-step).

Thanks
July 2, 2004 12:19 AM
 

ok said:

July 18, 2004 12:29 AM
 

alice said:

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

July 22, 2004 8:25 PM
 

Occasionally Connected said:

How can I update my user interface from another thread? How can I update my user interface from another thread? 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. A must read for those who have free-threaded code that wants to side-effect the UI. This is an often misunderstood aspect of Windows programming and is long-standing since the advent of Win16. Way back then ... you typically only had one process and one thread. But with today's programs that are performing background tasks (like pulling RSS feeds), checking email, performing asynchronous web services calls, etc. you can easily find yourself running on a thread that doesn't have UI affinity (i.e. you're not running on the thread that the UI objects were created on). Be sure to take the time to...
July 28, 2004 4:33 PM
 

RebelGeekz said:

December 28, 2004 4:53 AM
 

aheil.de blog said:

May 17, 2006 6:22 PM
 

.NET Compact Framework - Updating the User Interface from a Worker Thread « Mike’s Dump said:

September 8, 2007 7:45 PM
Anonymous comments are disabled

© 2008 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker