Source: C # calls controls across threads
In C # application development, we often separate the UI thread from the worker thread to prevent the interface from stopping responding. At the same time we need to update the controls on the UI interface in the worker thread,
Here are a few common methods
Read Catalogue
- Invalid inter-thread operation
- The first approach: prohibit the compiler from checking cross-thread access
- Second approach: Use delegate and invoke to invoke controls from other threads
- Third approach: Use delegate and BeginInvoke to control controls from other threads
- Fourth approach: using the BackgroundWorker component
- Source code Download
Invalid inter-thread operation
There is a button and a label on the interface, and clicking the button initiates a thread to update the value of the label
Private voidButton1_Click (Objectsender, EventArgs e) {Thread Thread1=NewThread (NewParameterizedthreadstart (Updatelabel)); Thread1. Start ("Update Label"); } Private voidUpdatelabel (Objectstr) { This. Label1. Text =Str. ToString (); }
After running, the program will error "Invalid cross-threading operation, access it from a thread that is not creating" Label1 "
This is because. NET prohibits invoking a control across threads, otherwise anyone can manipulate the control, which may eventually cause an error.
Here are a few ways to call controls across threads
The first approach: prohibit the compiler from checking cross-thread access
This is the simplest approach, which is equivalent to not checking for conflicts between threads, allowing threads to be arbitrarily messed up, and finally Lable1 what the value of the control is ( This method is not recommended )
Public Form1 () { InitializeComponent (); // Join this line false ; }
Second approach: Use delegate and invoke to invoke controls from other threads
Invoking the control's Invoke method, you can control the control, for example
Private voidButton2_Click (Objectsender, EventArgs e) {Thread Thread1=NewThread (NewParameterizedthreadstart (UpdateLabel2)); Thread1. Start ("Update Label"); } Private voidUpdateLabel2 (Objectstr) { if(Label2. invokerequired) {//when a control's InvokeRequired property value is true, it is stated that a thread other than the one that created it wants to access itaction<string> actiondelegate = (x) + = { This. Label2. Text =x.tostring ();}; //or//action<string> actiondelegate = delegate (string txt) {this.label2.Text = txt;}; This. Label2. Invoke (Actiondelegate, str); } Else { This. Label2. Text =Str. ToString (); } }
Third approach: Use delegate and BeginInvoke to control controls from other threads
Just put the above this.label2.Invoke (Actiondelegate, str); Change the BeginInvoke method to the
The difference between the Invoke method and the BeginInvoke method is
The Invoke method is synchronous, and it waits for the worker thread to finish,
The BeginInvoke method is asynchronous, and it will start another thread to complete the worker thread
Fourth approach: Using the BackgroundWorker component (this method is recommended)
BackgroundWorker is a control that is used in. NET to perform multi-threaded tasks, allowing programmers to perform some operations on a separate thread. Time-consuming operations, such as downloads and database transactions. Simple to use
Private voidButton4_Click (Objectsender, EventArgs e) { using(BackgroundWorker bw =NewBackgroundWorker ()) {bw. RunWorkerCompleted+=NewRunworkercompletedeventhandler (bw_runworkercompleted); Bw. DoWork+=NewDoworkeventhandler (bw_dowork); Bw. RunWorkerAsync ("Tank"); } } voidBw_dowork (Objectsender, DoWorkEventArgs e) { //here is the background thread, which is done on the other thread//This is a working thread that really does things.//you can do some time-consuming, complex operations here .Thread.Sleep ( the); E.result= E.argument +"Worker Threads Complete"; } voidBw_runworkercompleted (Objectsender, Runworkercompletedeventargs e) { //The background thread is now complete and the main thread is returned, so you can use the UI control directly This. label4. Text =e.result.tostring (); }
C # calls controls across threads