Source: Http://www.tuicool.com/articles/FNzURb
Overview
In C#winform programming, the practice of updating UI controls directly across threads is incorrect, and there are often "invalid inter-thread operations: access to it from a thread that is not a control created" exception. There are 4 common ways to handle updating WinForm UI controls across threads:
1. Update through the SynchronizationContext Post/send method of the UI thread;
2. Update through the Invoke/begaininvoke method of the UI control;
3. Perform asynchronous operations with BackgroundWorker instead of thread;
4. Avoid "Cross-threading exceptions" (Non-thread-safe, not recommended) by setting form properties and canceling thread safety checks.
The following 3 methods of application of the above examples, I hope that the first knowledge of C # WinForm students have some help.
The writing table shares the meaning of communication, the level of fear is limited, the text of the understanding and expression of the error is also asked to be criticized.
Body
1.
Usage:
//A total of three steps//First step: Get the UI thread synchronization context (in the form constructor or Formload event)/// <summary>///Synchronization context for the UI thread/// </summary> SynchronizationContext M_synccontext =NullPublic Form1 () {InitializeComponent ();//Get UI thread Synchronization contextm_synccontext = synchronizationcontext.current;//Control.checkforillegalcrossthreadcalls = false; }//Step two: Define the thread's principal method/// <summary>///Thread's principal method/// </summary>Privatevoid Threadprocsafepost () {//... Perform thread tasks//Updating UI in thread (synchronizing context m_synccontext through UI threads)M_synccontext.post(Settextsafepost,"This text is set safely by Synchronizationcontext-post. ");//... Perform thread Other tasks}//Step three: Define methods for updating UI controls/// <summary>///Ways to update text box contents/// </summary>/// <param name= "Text" ></param>PrivatevoidSettextsafepost(Object text) {This.textBox1.Text = Text. ToString (); }//After that, the thread is started/// <summary> /// Start Thread button event /// </summary> /// <param name= "sender" ></param> /// <param name= "E" ></param> private void Setsafepostbtn_click (object sender, EventArgs e) {this.demothread = span class= "keyword" >new Thread (new threadstart (this. Threadprocsafepost)); this.demothread.start ();
Note: The three bold parts are the key. The main principle of this method is: During thread execution, the data that needs to be updated to the UI control is no longer updated directly, but is sent to the UI thread's message queue in the form of an asynchronous/synchronous message via the Post/send method of the UI thread context, after the UI thread receives the message. Depending on whether the message is an asynchronous message or a synchronous message, the Settextsafepost method is called asynchronously/synchronously to update its own control directly.
In essence, the message sent to the UI thread is not simple data, but rather a delegate invokes the command.
Updating UI in thread (synchronizing context m_synccontext through UI threads)
M_synccontext.post ( settextsafepost , "This text is set safely by Synchronizationcontext-post.");
You can interpret this line of code by submitting an asynchronous message to the UI thread's synchronization context (M_synccontext) (the UI thread, which executes the delegate asynchronously after you receive the message, invokes the method Settextsafepost, and the argument is "this text Was ... ").
2. Updating via the Invoke/begaininvoke method of the UI control
Usage: Similar to Method 1, it can be divided into three steps.
//A total of three steps//First step: Define the delegate type//delegate type of interface control to update textDelegatevoidSettextcallback(string text);//Step two: Define the thread's principal method/// <summary>///Thread's principal method/// </summary>Privatevoid Threadprocsafe () {//... Perform thread tasks//Update UI in thread (via the control's. Invoke method)This.SetText("This text is set safely. ");//... Perform thread Other tasks}//Step three: Define methods for updating UI controls/// <summary>///Ways to update text box contents/// </summary>/// <param name= "Text" ></param>PrivatevoidSetText(String text) {//InvokeRequired required compares the thread ID of the//Calling thread to the thread ID of the creating thread.//If These threads is different, it returns true.if (this.textBox1.InvokeRequired)True if the thread that invokes the control is not the same as the thread that created the control.while (!this.textBox1.IsHandleCreated) {// resolves an exception that appears "Access disposed handle" when the form is closed if (this.textBox1.Disposing | |this.textBox1.IsDisposed)Return } Settextcallback D =New Settextcallback (SetText); This.Textbox1.invoke(d,NewObject[] {text}); }else {This.textBox1.Text = Text; } }//After that, the thread is started/// <summary> /// Start Thread button event /// </summary> /// <param name= "sender" ></param> /// <param name= "E" ></param> private void Settextsafebtn_click (object sender, EventArgs e) {this.demothread = span class= "keyword" >new Thread (new threadstart (this. Threadprocsafe)); this.demothread.start ();
Description: This method is currently the mainstream method of updating the UI across threads, using the Invoke/begaininvoke method of the control to move the delegate to the UI thread called to implement thread-safe updates. The principle is similar to Method 1, in essence, the message to be submitted in the thread is passed to the UI thread through the control handle invocation delegate.
Resolves a "Access disposed handle" Exception section when the form closes Code reference blog Park-affairs classmate's article.
3.
Usage:
//A total of three steps//First step: Define the BackgroundWorker object and register the event (thread body execution, UI update event)Private BackgroundWorker BackgroundWorker1 =NullPublic Form1 () {InitializeComponent (); backgroundWorker1 =New System.ComponentModel.BackgroundWorker ();//Set up report progress updatesbackgroundworker1.workerreportsprogress = true; //Registering thread Body method Backgroundworker1.dowork + =New Doworkeventhandler (backgroundworker1_dowork);//Registering the Update UI method Backgroundworker1.progresschanged + =New Progresschangedeventhandler (backgroundworker1_progresschanged);//backgroundworker1.runworkercompleted + = new System.ComponentModel.RunWorkerCompletedEventHandler ( this.backgroundworker1_runworkercompleted); }//Step two: Define the execution thread body event//Thread Principal methodPublicvoid Backgroundworker1_dowork (Object sender, DoWorkEventArgs e) {//... Perform thread tasks//Update UI in Thread (via ReportProgress method)backgroundworker1.reportprogress(50, "this text is set safely by BackgroundWorker." span class= "comment" >// ... Perform thread other tasks} // step three: Define the Execute UI update event // ui Update method public void backgroundworker1_ ProgressChanged (object sender, ProgressChangedEventArgs e) { This.textBox1.Text = E.userstate.tostring (); } //// Start BackgroundWorker private void settextbackgroundworkerbtn_click ( span class= "keyword" >object sender, EventArgs e) {this.backgroundworker1.runworkerasync ();}
Description: BackgroundWorker is a good choice when performing asynchronous tasks in C # WinForm. It is the product of the EAP (Event based Asynchronous Pattern) thought, DoWork is used to perform asynchronous tasks, and after the execution of the task/execution, we can pass progresschanged, The progresscompleteded event is a thread-safe UI update.
Note that://Set Report progress Update
backgroundworker1.workerreportsprogress = true;
By default BackgroundWorker is not reporting progress and needs to be displayed to set report progress properties.
4. Avoid "Invalid inter-threading exception" (Non-thread safe, recommended not to use) by setting form properties and canceling thread safety checks
Usage: Checkforillegalcrossthreadcalls The static property of the control class to false.
Public Form1 () { InitializeComponent (); // specifies that the call to the wrong thread no longer catches false; }
Description: By setting the Checkforillegalcrossthreadcalls property, you can indicate whether to catch non-secure operation exceptions between threads. The property value defaults to Ture, that is, the non-thread-to-threads operation is to catch exceptions ("Invalid Inter-Threading" exception). By setting this property to False, the exception is simply masked. Control.checkforillegalcrossthreadcalls's comments are as follows
//// Summary: // Gets or sets a value that indicates whether calls to the wrong thread are captured, which access the control's System.Windows.Forms.Control.Handle when the application is debugged // property. ///// returns the result: // True if a call to the wrong thread was caught; otherwise false. [Editorbrowsable (editorbrowsablestate.advanced)] [DesignerSerializationVisibility (Designerserializationvisibility.hidden)] [Srdescription ("controlcheckforillegalcrossthreadcalls")] [browsable (false)] Public Static bool Checkforillegalcrossthreadcalls { get; set;}
Review:
The 4 methods described in the article, the first three are thread-safe, can be used in the actual project of local circumstances. The last method is non-thread safe, and beginners can experiment with it but not recommend it.
The following list compares these four ways
method |
thread safety |
strong> supports asynchronous / synchronization |
other |
U I sync Context Update |
Yes |
post/send |
try to The form constructor, formload gets the synchronization context |
control Invoke |
Yes |
control. Invoke/begaininvoke |
Note Check that the control handle is freed |
backgroundworker more New |
Yes |
progresschanged, runworkercompleted Event synchronization update |
report Progress |
checkforillegalcrossthreadcalls Cancel call checking across threads |
no |
synchronous update |
simple, not recommended |