Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
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, SpainAnonymous
March 17, 2004
The comment has been removedAnonymous
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 removedAnonymous
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
AbdullahAnonymous
July 01, 2004
Please, clearly explain to me about the way to create the user-interface thread(step-by-step).
ThanksAnonymous
July 01, 2004
Please, clearly explain to me about the way to create the user-interface thread(step-by-step).
ThanksAnonymous
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 removedAnonymous
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=55Anonymous
January 21, 2009
PingBack from http://www.keyongtech.com/433106-best-way-to-design-multithreadingAnonymous
January 24, 2009
PingBack from http://vdplaat.dnsalias.com/wp/?p=602Anonymous
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 ModelsAnonymous
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 removedAnonymous
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.comAnonymous
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 removedAnonymous
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,