How to: make thread-safe calls to Windows Forms controls

Source: Internet
Author: User

Example

Access to Windows Forms controls is not thread-safe in nature. If two or more threads operate on the status of a control, the control may be forced to enter an inconsistent state. Other thread-related bugs may also occur, including contention and deadlocks. It is important to ensure that controls are accessed in a thread-safe manner.

. NET Framework helps detect this issue when accessing controls in a non-thread-safe manner. When running an application in the debugger, if a thread other than the thread that creates a control tries to call the control, the debugger will throw an InvalidOperationException and prompt the message "never create a controlControl nameThe thread to access it ."

This exception occurs reliably during debugging and in some cases during runtime. We strongly recommend that you fix this issue when this error message is displayed. This exception may occur when you debug applications written in. NET Framework before. NET Framework 2.0.

Note:

You can set the value of the checkforillegalcrossthreadcils attributeFalseTo disable this exception. This causes the control to run in the same way as in Visual Studio 2003.

The following code example demonstrates how to call a Windows form control from a third thread in the thread-safe and non-thread-safe mode. It demonstrates a method to set the Text attribute of the TextBox Control in non-thread-safe mode, and two methods to set the Text attribute in thread-safe mode.TextAttribute method.

C #
using System;using System.ComponentModel;using System.Threading;using System.Windows.Forms;namespace CrossThreadDemo{public class Form1 : Form{// This delegate enables asynchronous calls for setting// the text property on a TextBox control.delegate void SetTextCallback(string text);// This thread is used to demonstrate both thread-safe and// unsafe ways to call a Windows Forms control.private Thread demoThread = null;// This BackgroundWorker is used to demonstrate the // preferred way of performing asynchronous operations.private BackgroundWorker backgroundWorker1;private TextBox textBox1;private Button setTextUnsafeBtn;private Button setTextSafeBtn;private Button setTextBackgroundWorkerBtn;private System.ComponentModel.IContainer components = null;public Form1(){InitializeComponent();}protected override void Dispose(bool disposing){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 void setTextUnsafeBtn_Click(object sender,EventArgs e){this.demoThread =new Thread(new ThreadStart(this.ThreadProcUnsafe));this.demoThread.Start();}// This method is executed on the worker thread and makes// an unsafe call on the TextBox control.private void ThreadProcUnsafe(){this.textBox1.Text = "This text was set unsafely.";}// This event handler creates a thread that 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();}// This method is executed on the worker thread and makes// a thread-safe call on the TextBox control.private void ThreadProcSafe(){this.SetText("This text was set safely.");}// This method 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 that created// the TextBox control, the Text property 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;}}// 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 void setTextBackgroundWorkerBtn_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 void backgroundWorker1_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e){this.textBox1.Text ="This text was set safely by BackgroundWorker.";}#region Windows Form Designer generated codeprivate void InitializeComponent(){this.textBox1 = new System.Windows.Forms.TextBox();this.setTextUnsafeBtn = new System.Windows.Forms.Button();this.setTextSafeBtn = new System.Windows.Forms.Button();this.setTextBackgroundWorkerBtn = new System.Windows.Forms.Button();this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();this.SuspendLayout();// // textBox1// this.textBox1.Location = new System.Drawing.Point(12, 12);this.textBox1.Name = "textBox1";this.textBox1.Size = new System.Drawing.Size(240, 20);this.textBox1.TabIndex = 0;// // setTextUnsafeBtn// this.setTextUnsafeBtn.Location = new System.Drawing.Point(15, 55);this.setTextUnsafeBtn.Name = "setTextUnsafeBtn";this.setTextUnsafeBtn.TabIndex = 1;this.setTextUnsafeBtn.Text = "Unsafe Call";this.setTextUnsafeBtn.Click += new System.EventHandler(this.setTextUnsafeBtn_Click);// // setTextSafeBtn// this.setTextSafeBtn.Location = new System.Drawing.Point(96, 55);this.setTextSafeBtn.Name = "setTextSafeBtn";this.setTextSafeBtn.TabIndex = 2;this.setTextSafeBtn.Text = "Safe Call";this.setTextSafeBtn.Click += new System.EventHandler(this.setTextSafeBtn_Click);// // setTextBackgroundWorkerBtn// this.setTextBackgroundWorkerBtn.Location = new System.Drawing.Point(177, 55);this.setTextBackgroundWorkerBtn.Name = "setTextBackgroundWorkerBtn";this.setTextBackgroundWorkerBtn.TabIndex = 3;this.setTextBackgroundWorkerBtn.Text = "Safe BW Call";this.setTextBackgroundWorkerBtn.Click += new System.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 Form Controls

The non-thread-safe call Method for Windows Form Controls is directly called from the auxiliary thread. When an application is called, the debugger triggersInvalidOperationException, Warning that the call to the control is not thread-safe.

C #
// This event handler creates a thread that calls a // Windows Forms control in an unsafe way.private void setTextUnsafeBtn_Click(object sender,EventArgs e){this.demoThread =new Thread(new ThreadStart(this.ThreadProcUnsafe));this.demoThread.Start();}// This method is executed on the worker thread and makes// an unsafe call on the TextBox control.private void ThreadProcUnsafe(){this.textBox1.Text = "This text was set unsafely.";}
Thread-safe calls to Windows Forms controls thread-safe calls to Windows Forms controls
  1. Query the InvokeRequired property of the control.

  2. IfInvokeRequiredReturnTrueThe actual call control delegate is used to call Invoke.

  3. IfInvokeRequiredReturnFalseTo directly call the control.

In the following code example, the logic is calledSetText. NameSetTextDelegateDelegate type EncapsulationSetTextMethod.TextBoxControlInvokeRequiredReturnTrue,SetTextMethod CreationSetTextDelegateAnd callInvokeMethod. This makesSetTextMethod createdTextBoxControl thread calls, and will be directly set in this thread ContextTextAttribute.

C #
// This event handler creates a thread that 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();}// This method is executed on the worker thread and makes// a thread-safe call on the TextBox control.private void ThreadProcSafe(){this.SetText("This text was set safely.");}
C # // This method demonstrates a pattern for making thread-safe
// Callon a Windows Forms control.
//
// If the calling thread is different from the thread that
// Created the TextBox control, this method creates
// SetTextCallback and callitself asynchronously using
// Invoke method.
//
// If the calling thread is the same as the thread that created
// The TextBox control, the Text property is set directly.
Private void SetText (string text)
{
// InvokeRequired required compares the thread ID of
// 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;
}
} Secure thread call using BackgroundWorker

The first choice for implementing multithreading in applications is to use the BackgroundWorker component.BackgroundWorkerThe component uses the event-driven model to implement multithreading. The auxiliary thread runs the DoWork event handler, and the control creation thread runs the ProgressChanged and RunWorkerCompleted event handlers. Be sure notDoWorkThe event handler calls any of your controls.

The following code example does not asynchronously execute any work, so there is noDoWorkThe implementation of the event handler.TextBoxControlTextAttribute inRunWorkerCompletedDirectly set in the event handler.

C #
// 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 void setTextBackgroundWorkerBtn_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 void backgroundWorker1_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e){this.textBox1.Text ="This text was set safely by BackgroundWorker.";}
ActiveX controls on Windows Forms

If ActiveX controls are used on the form, you may receiveInvalidOperationException. In this case, ActiveX controls do not support multithreading. For more information about ActiveX controls using Windows Forms, see Windows Forms and unmanaged applications.

If you are using Visual Studio, you can disable the Visual Studio host process to prevent this exception.

Reliable Programming
Warning

When using any type of multithreading, the code is prone to very serious and complex bugs. For more information, see best practices for hosted thread processing before implementing any solution that uses multithreading.

See task

How to: run operations in the background
How to: implement a form that uses background operations
Reference

BackgroundWorker
Other resources

Use. NET Framework to develop custom Windows Forms controls
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.