Usin Invoke with threads
-
I have a piece of code which runs in another thread (not the UI thread). // listBox1.Items.Add(s); // But because listBox1 was created in another thread, VS2005 does not allow me to do this. I have been told that I need to use BeginInvoke or Invoke on the control to add the item. Does anyone have any ideas on how I would code that? I need to pass a string which will hold the new string to add listBox1. Thanks in advance. John Young Yippee Kai Yai Signed Polomint.......
-
I have a piece of code which runs in another thread (not the UI thread). // listBox1.Items.Add(s); // But because listBox1 was created in another thread, VS2005 does not allow me to do this. I have been told that I need to use BeginInvoke or Invoke on the control to add the item. Does anyone have any ideas on how I would code that? I need to pass a string which will hold the new string to add listBox1. Thanks in advance. John Young Yippee Kai Yai Signed Polomint.......
Something like this should do it:
using System;
using System.IO;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;class test : System.Windows.Forms.Form
{public delegate void Add(string s); public ListBox box; public Button button; public test() { InitializeComponents(); } public void InitializeComponents() { box = new ListBox(); button = new Button(); button.Location = new Point(70, 120); button.Text = "Click Me"; button.Click += new EventHandler(button\_Click); this.Controls.Add(box); this.Controls.Add(button); } private void StringAdder(string s) { box.Items.Add(s); } private void button\_Click(object sender, EventArgs e) { Thread t = new Thread(new ThreadStart(StartThread)); t.Start(); } private void StartThread() { Add a = new Add(StringAdder); for(int i = 0; i < 100000; i++) { IAsyncResult ar = a.BeginInvoke("Nick", null, null); } } \[STAThread\] public static void Main() { Application.Run(new test()); }
}
- Nick Parker
My Blog | My Articles -
Something like this should do it:
using System;
using System.IO;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;class test : System.Windows.Forms.Form
{public delegate void Add(string s); public ListBox box; public Button button; public test() { InitializeComponents(); } public void InitializeComponents() { box = new ListBox(); button = new Button(); button.Location = new Point(70, 120); button.Text = "Click Me"; button.Click += new EventHandler(button\_Click); this.Controls.Add(box); this.Controls.Add(button); } private void StringAdder(string s) { box.Items.Add(s); } private void button\_Click(object sender, EventArgs e) { Thread t = new Thread(new ThreadStart(StartThread)); t.Start(); } private void StartThread() { Add a = new Add(StringAdder); for(int i = 0; i < 100000; i++) { IAsyncResult ar = a.BeginInvoke("Nick", null, null); } } \[STAThread\] public static void Main() { Application.Run(new test()); }
}
- Nick Parker
My Blog | My ArticlesNo, that will end up on a thread-pool worker thread. You need to use Control.Invoke (or BeginInvoke) to get back onto the user-interface thread. Control is a placeholder: it's an instance member, so you need to supply a
Control
or a class derived fromControl
on the left of .Invoke. The fact that your code sometimes works in .NET 1.x is an accident. There's always a possibility of race conditions or deadlocks. Some controls work, others don't. Typically you'd Invoke on the form itself, e.g.:private void StartThread()
{
Add a = new Add(StringAdder);
object[] args = new object[] { "Mike" };for(int i = 0; i < 100000; i++)
{
this.Invoke( a, args );
}
}(shamelessly stealing Nick's example). You'd BeginInvoke rather than Invoke if you wanted the UI notification to happen asynchronously. Invoke waits for the UI thread to finish processing the call before continuing. Some sources suggest always using BeginInvoke since you can't know how busy the UI is going to be, and you can end up deadlocking in some situations. This is the equivalent of using PostMessage versus SendMessage in C++ code. Windows Forms 2.0 enforces the correct model: it always throws if you try to update UI from the wrong thread. Stability. What an interesting concept. -- Chris Maunder
-
No, that will end up on a thread-pool worker thread. You need to use Control.Invoke (or BeginInvoke) to get back onto the user-interface thread. Control is a placeholder: it's an instance member, so you need to supply a
Control
or a class derived fromControl
on the left of .Invoke. The fact that your code sometimes works in .NET 1.x is an accident. There's always a possibility of race conditions or deadlocks. Some controls work, others don't. Typically you'd Invoke on the form itself, e.g.:private void StartThread()
{
Add a = new Add(StringAdder);
object[] args = new object[] { "Mike" };for(int i = 0; i < 100000; i++)
{
this.Invoke( a, args );
}
}(shamelessly stealing Nick's example). You'd BeginInvoke rather than Invoke if you wanted the UI notification to happen asynchronously. Invoke waits for the UI thread to finish processing the call before continuing. Some sources suggest always using BeginInvoke since you can't know how busy the UI is going to be, and you can end up deadlocking in some situations. This is the equivalent of using PostMessage versus SendMessage in C++ code. Windows Forms 2.0 enforces the correct model: it always throws if you try to update UI from the wrong thread. Stability. What an interesting concept. -- Chris Maunder
Ok, I understand what you are both saying. Would this work? Also the line
Add a = new Add(StringAdder);
has me confused. What is add? The compiler complains about me missing a Using directive.string s; s = "Timeout"; Add a = new Add(StringAdder); IAsyncResult ar = a.BeginInvoke(s, null, null); //lbLog.Items.Add(s);
Thanks again. PS: What about things like listBox1.Items.Clear() etc... Yippee Kai Yai Signed Polomint....... -
No, that will end up on a thread-pool worker thread. You need to use Control.Invoke (or BeginInvoke) to get back onto the user-interface thread. Control is a placeholder: it's an instance member, so you need to supply a
Control
or a class derived fromControl
on the left of .Invoke. The fact that your code sometimes works in .NET 1.x is an accident. There's always a possibility of race conditions or deadlocks. Some controls work, others don't. Typically you'd Invoke on the form itself, e.g.:private void StartThread()
{
Add a = new Add(StringAdder);
object[] args = new object[] { "Mike" };for(int i = 0; i < 100000; i++)
{
this.Invoke( a, args );
}
}(shamelessly stealing Nick's example). You'd BeginInvoke rather than Invoke if you wanted the UI notification to happen asynchronously. Invoke waits for the UI thread to finish processing the call before continuing. Some sources suggest always using BeginInvoke since you can't know how busy the UI is going to be, and you can end up deadlocking in some situations. This is the equivalent of using PostMessage versus SendMessage in C++ code. Windows Forms 2.0 enforces the correct model: it always throws if you try to update UI from the wrong thread. Stability. What an interesting concept. -- Chris Maunder
Mike Dimmick wrote: Invoke waits for the UI thread to finish processing the call before continuing In my test example, I didn't want to wait, which is why I went with the asynchronous call. Mike Dimmick wrote: Windows Forms 2.0 enforces the correct model: it always throws if you try to update UI from the wrong thread. Hmm, I will have to check this out at home, I don't have Visual Studio 2005 here at work. - Nick Parker
My Blog | My Articles -
Ok, I understand what you are both saying. Would this work? Also the line
Add a = new Add(StringAdder);
has me confused. What is add? The compiler complains about me missing a Using directive.string s; s = "Timeout"; Add a = new Add(StringAdder); IAsyncResult ar = a.BeginInvoke(s, null, null); //lbLog.Items.Add(s);
Thanks again. PS: What about things like listBox1.Items.Clear() etc... Yippee Kai Yai Signed Polomint.......polomint wrote: What is add?
Add
was defined as adelegate
. You can read more about it here[^]. If you noticed, theStringAdder
method I wrote matched the method signature defined in theAdd
delegate
. It basically allows me to treatStringAdder
as a callback function when theBeginInvoke
method is called from another thread. - Nick Parker
My Blog | My Articles -
polomint wrote: What is add?
Add
was defined as adelegate
. You can read more about it here[^]. If you noticed, theStringAdder
method I wrote matched the method signature defined in theAdd
delegate
. It basically allows me to treatStringAdder
as a callback function when theBeginInvoke
method is called from another thread. - Nick Parker
My Blog | My Articles -
No, that will end up on a thread-pool worker thread. You need to use Control.Invoke (or BeginInvoke) to get back onto the user-interface thread. Control is a placeholder: it's an instance member, so you need to supply a
Control
or a class derived fromControl
on the left of .Invoke. The fact that your code sometimes works in .NET 1.x is an accident. There's always a possibility of race conditions or deadlocks. Some controls work, others don't. Typically you'd Invoke on the form itself, e.g.:private void StartThread()
{
Add a = new Add(StringAdder);
object[] args = new object[] { "Mike" };for(int i = 0; i < 100000; i++)
{
this.Invoke( a, args );
}
}(shamelessly stealing Nick's example). You'd BeginInvoke rather than Invoke if you wanted the UI notification to happen asynchronously. Invoke waits for the UI thread to finish processing the call before continuing. Some sources suggest always using BeginInvoke since you can't know how busy the UI is going to be, and you can end up deadlocking in some situations. This is the equivalent of using PostMessage versus SendMessage in C++ code. Windows Forms 2.0 enforces the correct model: it always throws if you try to update UI from the wrong thread. Stability. What an interesting concept. -- Chris Maunder
Yep, your right, I can do it in .NET 1.1 but 2.0 doesn't like it. In fact, Visual Studio shows this error: - Nick Parker
My Blog | My Articles