In a single-threaded WINFOM program, setting the value of a control is a very easy thing to do directly with this. Textbox1.value = "Hello world!"; It's done, but if you do it in a new thread, like this:
private void Btnset_click (object sender, EventArgs e)
{
Thread t = new Thread (new Parameterizedthreadstart (Settextboxvalue));
Of course, you can also write the thread t = new Thread (settextboxvalue) with an anonymous delegate;
T.start ("Hello World");
}
void Settextboxvalue (Object obj)
{
This.textBox1.Text = obj. ToString ();
}
At run time, a ruthless error is reported:
Invalid inter-thread operation: access it from a thread that is not creating the control "TextBox1".
The reason, the UI control in WinForm is not thread-safe, if you can arbitrarily change its value in any thread, you create a thread, I create a thread, everyone to rob to change the value of "TextBox1", without any order, chaos ...
Workaround:
1. Deceiving method (Control.checkforillegalcrossthreadcalls = false;)--Only WinForm valid
Using System;
Using System.Threading;
Using System.Windows.Forms;
Namespace ThreadTest
{
public partial class Form1:form
{
Public Form1 ()
{
InitializeComponent ();
Control.checkforillegalcrossthreadcalls = false;//This line is the key
}
private void Btnset_click (object sender, EventArgs e)
{
Thread t = new Thread (new Parameterizedthreadstart (Settextboxvalue));
T.start ("Hello World");
}
void Settextboxvalue (Object obj)
{
This.textBox1.Text = obj. ToString ();
}
}
}
Set Control.checkforillegalcrossthreadcalls to False, the equivalent of not detecting conflicts between threads, allowing the route to random, of course, the final TextBox1 value is what unpredictable, only God knows, But it's also the least-effort way.
2. Using delegate invocation-the most common approach (only WinForm valid)
Using System;
Using System.Threading;
Using System.Windows.Forms;
Namespace ThreadTest
{
public partial class Form1:form
{
delegate void D (object obj);
Public Form1 ()
{
InitializeComponent ();
}
private void Btnset_click (object sender, EventArgs e)
{
Thread t = new Thread (new Parameterizedthreadstart (Settextboxvalue));
T.start ("Hello World");
}
void Settextboxvalue (Object obj)
{
if (textbox1.invokerequired)
{
D d = new D (delegatesetvalue);
Textbox1.invoke (D,obj);
}
Else
{
This.textBox1.Text = obj. ToString ();
}
}
void Delegatesetvalue (Object obj)
{
This.textBox1.Text = obj. ToString ();
}
}
}
3. Using the SynchronizationContext context-the most mysterious method (Winform/silverlight can be used)
It's mysterious because the official MSDN explanation is said to be unclear.
Using System;
Using System.Threading;
Using System.Windows.Forms;
Namespace ThreadTest
{
public partial class Form1:form
{
Public Form1 ()
{
InitializeComponent ();
}
private void Btnset_click (object sender, EventArgs e)
{
Thread t = new Thread (new Parameterizedthreadstart (Run));
Mypram _p = new Mypram () {context = synchronizationcontext.current, parm = "Hello World"};
T.start (_p);
}
void Run (Object obj)
{
Mypram p = obj as Mypram;
P.context.post (Settextvalue, p.parm);
}
void Settextvalue (Object obj)
{
This.textBox1.Text = obj. ToString ();
}
}
public class Mypram
{
Public SynchronizationContext Context {set; get;}
Public object Parm {set; get;}
}
}
4. Using BackgroundWorker-the most lazy approach (Winform/silverlight Universal)
BackgroundWorker will be in the main thread outside, another background thread, we can put some processing in the background thread processing, after completion, the background thread will pass the results to the main thread, and end themselves.
Using System;
Using System.ComponentModel;
Using System.Windows.Forms;
Namespace ThreadTest
{
public partial class Form1:form
{
Public Form1 ()
{
InitializeComponent ();
}
private void Btnset_click (object sender, EventArgs e)
{
MessageBox.Show (Thread.CurrentThread.ManagedThreadId.ToString ());
using (BackgroundWorker bw = new BackgroundWorker ())
{
Bw. runworkercompleted + = new Runworkercompletedeventhandler (bw_runworkercompleted);
Bw. DoWork + = new Doworkeventhandler (bw_dowork);
Bw. RunWorkerAsync ("Hello World");
}
}
void Bw_dowork (object sender, DoWorkEventArgs e)
{
MessageBox.Show (Thread.CurrentThread.ManagedThreadId.ToString ());
E.result = e.argument;//Here is simply to return the parameter as a result, of course, you can also do complex processing here, and then return the results you want (here the operation is done on another thread)
}
void Bw_runworkercompleted (object sender, Runworkercompletedeventargs e)
{
The background thread is now complete and the main thread is returned, so you can use the UI control directly
This.textBox1.Text = E.result.tostring ();
MessageBox.Show (Thread.CurrentThread.ManagedThreadId.ToString ());
}
}
}
5.dispatcher.begininvoke--silverlight's unique Cheats
CodeUsing System.Threading;
Using System.Windows.Controls;
Using System.Windows.Input;
Namespace ThreadTest
{
public partial class Mainpage:usercontrol
{
Public MainPage ()
{
InitializeComponent ();
}
private void Layoutroot_mouseleftbuttondown (object sender, MouseButtonEventArgs e)
{
Thread t = new thread (settextvalue);
T.start ("Hello World");
}
void Settextvalue (Object text)
{
This. Dispatcher.begininvoke (() = {This.txt.Text = Text. ToString (); });
}
}
}Turn from the http://www.cnblogs.com/yjmyzz/archive/2009/11/25/1610253.html under the Banyan Tree
Winform/silverlight How to update the value of a UI control in multithreaded programming