How to: Make Thread-safe calls to Windows Forms Controls _c# tutorial

Source: Internet
Author: User

Example

Accessing Windows forms controls is inherently not thread-safe. If two or more threads manipulate the state of a control, it may force the control into an inconsistent state. Other thread-related bugs may also occur, including contention and deadlocks. It is important to ensure that the control is accessed in a thread-safe manner.

The. NET Framework helps detect this problem when accessing controls in a way that is not thread-safe. When you run an application in the debugger, if a thread other than the thread that created the control attempts to invoke the control, the debugger raises a InvalidOperationException and prompts the message: "The control name is not created thread to access it. ”

This exception occurs reliably during debugging and in some cases at run time. It is strongly recommended that you fix this problem when you display this error message. This exception can occur when you debug an application written in the. NET Framework before version 2.0 of the. NET Framework.

Attention

You can disable this exception by setting the value of the Checkforillegalcrossthreadcalls property to false . This causes the control to run in the same way as in Visual Studio 2003.

The following code example demonstrates how to invoke a Windows forms control from a worker thread in a thread-safe manner and not in a thread-safe manner. It demonstrates a method for setting the Text property of a TextBox control in a way that is not thread-safe, and also shows two ways to set the text property in a thread-safe manner.

C#
UsingSystem;UsingSystem.ComponentModel;UsingSystem.Threading;UsingSystem.Windows.Forms;NamespaceCrossthreaddemo {Public ClassForm1:form {This is delegate enables asynchronous calls for setting The Text property is in a TextBox control.DelegatevoidSettextcallback (StringText);This thread are used to demonstrate both thread-safe and Unsafe ways to call a, Windows Forms control. PrivateThread DemoThread =Null;This backgroundworker was used to demonstrate the Preferred way of performing asynchronous operations. PrivateBackgroundWorker BackgroundWorker1;PrivateTextBox TextBox1;PrivateButton settextunsafebtn;PrivateButton settextsafebtn;PrivateButton settextbackgroundworkerbtn;PrivateSystem.ComponentModel.IContainer components =Null;PublicForm1 () {InitializeComponent ();}ProtectedOverridevoidDispose (booldisposing) {If(Disposing && (components!=Null) {components. Dispose (); }Base. Dispose (disposing); }This event handler creates a thread that calls a Windows Forms control in an unsafe way. Private voidSettextunsafebtn_click (object sender, EventArgs e) {This. DemoThread =NewThread (NewThreadStart (This. Threadprocunsafe));This. Demothread.start (); }This are executed on the worker thread and makes An unsafe call on the TextBox control. Private voidThreadprocunsafe () {This. TextBox1.Text = "This Text isSetUnsafely. ";}This event handler creates a thread that calls a Windows Forms control in a Thread-safe way. Private voidSettextsafebtn_click (object sender, EventArgs e) {This. DemoThread =NewThread (NewThreadStart (This. Threadprocsafe));This. Demothread.start (); }This are executed on the worker thread and makes A thread-safe call on the TextBox control. Private voidThreadprocsafe () {This. SetText ("This text isSetsafely. ");}This is demonstrates a pattern for making Thread-safe Calls on a Windows Forms control. // If The calling thread is different from the thread that Created the TextBox control, this method creates a Settextcallback and calls itself asynchronously using the Invoke method. // If The calling thread is the same as the thread of that created The TextBox control, the "Text" is set directly. Private voidSetText (StringText) {InvokeRequired required compares the thread ID of the Calling thread to the thread ID of the creating thread. If These threads are different, it returns true. If(This. textbox1.invokerequired) {Settextcallback d =NewSettextcallback (SetText);This. Invoke (D,NewObject[] {text}); }Else{This. TextBox1.Text = Text; } }This event handler starts the form ' s BackgroundWorker by calling RunWorkerAsync. // The Text property of the TextBox control is set When the BackgroundWorker raises the runworkercompleted Event. Private voidSettextbackgroundworkerbtn_click (object sender, EventArgs e) {This. Backgroundworker1.runworkerasync (); }This event handler sets the Text property of the TextBox Control. It is called on the thread that created the TextBox control, so the call is Thread-safe. // BackgroundWorker is the preferred way to perform asynchronous Operations. Private voidBackgroundworker1_runworkercompleted (object sender, Runworkercompletedeventargs e) {This. TextBox1.Text = "This Text isSetSafely by BackgroundWorker. ";} #region Windows Form Designer generated codePrivate voidInitializeComponent () {This. TextBox1 =NewSystem.Windows.Forms.TextBox ();This. settextunsafebtn =NewSystem.Windows.Forms.Button ();This. settextsafebtn =NewSystem.Windows.Forms.Button ();This. settextbackgroundworkerbtn =NewSystem.Windows.Forms.Button ();This. BackgroundWorker1 =NewSystem.ComponentModel.BackgroundWorker ();This. SuspendLayout ();// TextBox1 // This. textbox1.location =NewSystem.Drawing.Point (12, 12);This. Textbox1.name = "TextBox1";This. textbox1.size =NewSystem.Drawing.Size (240, 20);This. Textbox1.tabindex = 0;// Settextunsafebtn // This. settextunsafebtn.location =NewSystem.Drawing.Point (15, 55);This. Settextunsafebtn.name = "SETTEXTUNSAFEBTN";This. Settextunsafebtn.tabindex = 1;This. Settextunsafebtn.text = "Unsafe call";This. Settextunsafebtn.click + =NewSystem.EventHandler (This. Settextunsafebtn_click);// Settextsafebtn // This. settextsafebtn.location =NewSystem.Drawing.Point (96, 55);This. Settextsafebtn.name = "SETTEXTSAFEBTN";This. Settextsafebtn.tabindex = 2;This. Settextsafebtn.text = "Safe call";This. Settextsafebtn.click + =NewSystem.EventHandler (This. Settextsafebtn_click);// Settextbackgroundworkerbtn // This. settextbackgroundworkerbtn.location =NewSystem.Drawing.Point (177, 55);This. Settextbackgroundworkerbtn.name = "SETTEXTBACKGROUNDWORKERBTN";This. Settextbackgroundworkerbtn.tabindex = 3;This. Settextbackgroundworkerbtn.text = "Safe BW call";This. Settextbackgroundworkerbtn.click + =NewSystem.EventHandler (This. Settextbackgroundworkerbtn_click);////BackgroundWorker1 // this.backgroundWorker1.RunWorkerCompleted + =  New System.ComponentModel.RunWorkerCompletedEventHandler ( this.backgroundworker1_runworkercompleted); ////Form1 // this. ClientSize =  New System.Drawing.Size (268, 96);  this. Controls.Add ( this.settextbackgroundworkerbtn);  this. Controls.Add ( this.settextsafebtn);  this. Controls.Add ( this.settextunsafebtn);  this. Controls.Add ( this.textbox1);  this. Name = "Form1";  this. Text = "Form1";  this. ResumeLayout ( false);  this. PerformLayout (); #endregion [STAThread]  static  void Main () {application.enablevisualstyles (); Application.Run ( new Form1 ());}} }  

Non-thread-safe calls to Windows forms controls

Non-thread-safe invocation of Windows forms controls is called directly from a worker thread. When the application is invoked, the debugger throws a InvalidOperationExceptionwarning that the call to the control is not thread-safe.


C#
This event handler creates a thread that calls a 
new Thread newThreadStart (   

Thread-safe calls to Windows forms controls

To make a thread-safe call to a Windows forms control

  1. The InvokeRequired property of the query control.

  2. If invokerequired returns true, invoke Invoke is invoked using the delegate that actually invokes the control.

  3. If invokerequired returns false, the control is called directly.

In the following code example, this logic is implemented in a utility method called SetText . The delegate type named settextdelegate encapsulates the SetText method. When the invokerequired of a TextBox control returns True , theSetText method creates the settextdelegate And invokes the form's invoke method. This allows the SetText method to be invoked by the thread that created the TextBox control, and the text property is set directly in this thread context.

C #
 // This event handler creates a thread which calls a //Windows Forms control in a Thread-safe way.  private  void Settextsafebtn_click (object sender, EventArgs e) { this.demothread =  new Thread (
           
            new ThreadStart (
             this. Threadprocsafe));  This.demoThread.Start ();} The //This is executed on the worker thread and makes //a thread-safe call on the TextBox control.  Private  void Threadprocsafe () { this. SetText ("This text is  set safely.");         
             
C#
This is demonstrates a pattern for making Thread-safe
Calls on a Windows Forms control.
//
If The calling thread is different from the thread that
//created the TextBox control, this method creates a
//Settextcallback and calls itself asynchronously us ing the
//Invoke method.
//
//If The calling thread is the same as the thread this created
//The TextBox control, the Tex T is set directly.
private void SetText ( string text)
{
//invokerequired required compares the thread ID of the
//calling thread to the thread ID of the creating thread.
//If These threads are different, it returns true.
if ( this.textBox1.InvokeRequired)
{
Settextcallback d = new Settextcallback (SetText);
this. Invoke (d, new object[] {text});

Else
{
this.textBox1.Text = Text;
}
}
[[]] /span>

Thread-safe calls made using BackgroundWorker

The preferred way to implement multithreading in your applications is to use the BackgroundWorker component. The BackgroundWorker component uses the event-driven model to implement multithreading. The worker thread runs the DoWork event handler, and the thread that creates the control runs ProgressChanged and runworkercompleted event handlers. Be careful not to call any of your controls from the DoWork event handler.

The following code example does not perform any work asynchronously, so there is no implementation of the DoWork event handler. The Text property of the TextBox control is set directly in the runworkercompleted event handler.

C#
//This event handler starts the form ' s //BackgroundWorker by calling RunWorkerAsync. The ////The Text property of the TextBox control be set //When the BackgroundWorker raises the Runworkerc ompleted //event.  private  void Settextbackgroundworkerbtn_click (object sender, EventArgs e) { This.backgroundWorker1.RunWorkerAsync (); } //This event handler sets the "TextBox //control. It is called on the thread this created the //TextBox control, so the call is Thread-safe. ////BackgroundWorker is the preferred way to perform asynchronous //operations.  private  void backgroundworker1_runworkercompleted (object sender, Runworkercompletedeventargs e) { This.textBox1.Text = "This Text is  set safely by BackgroundWorker.";}       

ActiveX controls on Windows forms

If you use ActiveX controls on a form, you may receive InvalidOperationExceptionbetween threads when you run under the debugger. When this occurs, the ActiveX control does not support multithreading. For more information about ActiveX controls that use Windows Forms, see Windows Forms and unmanaged applications.

If you are using Visual Studio, you can prevent this exception by disabling the Visual Studio hosting process.

Reliable programming

Warning

With any kind of multithreading, code can easily produce very serious and complex bugs. For more information, see the best practices for managed threading before you implement any solution that uses multithreading.

Please see

How to: Implement a form that uses a background operation

reference BackgroundWorker

Windows Forms and unmanaged Applications

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.