Visual Studio 2005 is used to write a very simple program. It mainly creates a thread outside the main form to refresh the progress bar. This program has been written in Visual Studio 2003 and can run normally, but an exception occurs in Visual Studio 2005. "Inter-thread operations are invalid: they are not accessed from the thread where they are created ." Oh, later I found out that this is a new feature of 2005 ..Make thread-safe calls to Windows Forms controls When using multithreading to Improve the Performance of Windows Forms applications, you must call the control in thread-safe mode. 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: "it is never accessed by the thread that creates the control name of the control." 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 disable this exception by setting the value of the checkforillegalcrossthreadcils attribute to false. 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 security mode, and two methods to set the Text attribute in thread security mode. Program code using system; Using system. componentmodel; Using system. Threading; Using system. Windows. forms; // Http://msdn2.microsoft.com/zh-cn/library/ms171728.aspx#Mtps_DropDownFilterText Namespace crossthreaddemo { Public class form1: Form {// This proxy can call the setting text box Asynchronously Delegate void SetTextCallback (string text ); // This thread is used to demonstrate the two security threads and the insecure threads call the form for control. Private Thread demoThread = null; // A background work component that can be used for 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 method is triggered by a non-secure thread. Private void settextunsafebtn_click ( Object sender, Eventargs E) {// Create a thread and call the threadprocunsafe Method 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 () {// Unsafe thread: This. textbox1.text = "this text was set unsafely ."; } // This event handler creates a thread that calla // Windows Forms control in a thread-safe way. Private void settextsafebtn_click ( Object sender, Eventargs E) {// Same as non-secure, create a thread first. 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 () {// Security Execution Method 1: (1. Call a settext method to set the text of textbox .) This. settext ("this text was set safely ."); } Private void settext (string text) { // This method uses invokerequired to determine whether the call is from other threads. If (this. textbox1.invokerequired) // if it is from a non-main thread, execute the following { Settextcallback d = new settextcallback (settext); // use a proxy to make the proxy equal to the method itself. This. Invoke (D, new object [] {text}); // Let the main form thread call this method. } Else // when the main form calls this method and invokerequired is false, you can modify the text box in the main form thread. { 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. // The following is an asynchronous call using the backgroundworker component. Private void settextbackgroundworkerbtn_click ( Object sender, Eventargs E) {// When the button is pressed, call the runworkerasyne () method of the component to tell the component to start performing background operations. This. backgroundworker1.runworkerasync (); // The backgroundworker executes the content of backgroundworker1.dowork in the new thread. // If there is no dowork action, it will immediately return to the current thread to execute backgroundworker1.runworkercompleted } // This event handler sets the text property of the textbox // Control. It is called on the thread that created // Textbox Control, so the call is thread-safe. // // Backgroundworker is the preferred way to perform asynchronous // Operations. // // Private void backgroundworkerappsrunworkercompleted ( Object sender, Runworkercompletedeventargs E) { This. textbox1.text = "This text was set safely by BackgroundWorker ."; // This is executed in the main thread } # Region Windows Form Designer generated code Private 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. initialize mlayout (); } # Endregion [STAThread] Static void Main () { Application. EnableVisualStyles (); Application. Run (new Form1 ()); } } } I also wrote a more detailed BackgroundWorker application. Form1.csProgram code using System; Using System. Collections. Generic; Using System. ComponentModel; Using System. Data; Using System. Drawing; Using System. Text; Using System. Windows. Forms; Using System. Threading; Namespace safeThread { Public partial class Form1: Form { Public Form1 () { InitializeComponent (); } Delegate void del (int I ); Thread ThreadDemo; Private void button#click (object sender, EventArgs e) { ThreadDemo = new Thread (new ThreadStart (ThreadProSafe )); ThreadDemo. Start (); The toolStripStatusLabel2.Text = "operation is in progress .. "; Button1.Text = "in operation .."; This. Cursor = Cursors. WaitCursor; // This. Dispose (false ); } Private void ThreadProSafe () { Try { For (int I = 1; I <= 500; I ++) { Console. WriteLine (I ); SetProcess (int) (I/5 )); Thread. Sleep (5 ); } } Finally { SetSatus (0 ); } } Private void SetProcess (int vi) { If (InvokeRequired) { Del dd = new del (SetProcess ); This. Invoke (dd, new object [] {vi }); } Else { If (vi <= 100) This. progressBar1.Value = vi; } // Checkforillegalcrossthreadcils } Private void SetSatus (int vi) { If (InvokeRequired) { Del dd = new del (SetSatus ); This. Invoke (dd, new object [] {vi }); } Else { ToolStripStatusLabel2.Text = "operation ended! "; Button1.Text = "Start Operation "; This. Cursor = Cursors. Default; } } Private void button2_Click (object sender, EventArgs e) { If (Button) sender). Text = "background component operation ") { This. backgroundWorker1.RunWorkerAsync (10 ); This. button2.Text = "cancel background operations "; This. toolStripStatusLabel2.Text = "is being computed by the component background thread .. "; This. Cursor = Cursors. WaitCursor; } Else { BackgroundWorker1.CancelAsync (); This. toolStripStatusLabel2.Text = "is canceling .. "; } // MessageBox. Show ("OnClick:" + System. AppDomain. GetCurrentThreadId ()); } Private void backgroundworker=dowork (object sender, DoWorkEventArgs e) { For (int I = 1; I <= 500; I ++) { Console. WriteLine (I ); BackgroundWorker1.ReportProgress (int) (I/5 )); Thread. Sleep (5 ); If (backgroundWorker1.CancellationPending) { E. Cancel = true; Break; } } // Here is the program to be run in the background } Private void backgroundworkerappsrunworkercompleted (object sender, RunWorkerCompletedEventArgs e) { If (e. Cancelled) { ToolStripStatusLabel2.Text = "Operation canceled! "; } Else { ToolStripStatusLabel2.Text = "operation ended! "; } Button2.Text = "background component operation "; This. Cursor = Cursors. Default; Console. WriteLine ("aaa "); // MessageBox. Show ("RunWorkerCompleted:" + System. AppDomain. GetCurrentThreadId ()); } Private void backgroundWorker1_ProgressChanged (object sender, ProgressChangedEventArgs e) { This. progressbar1.value = E. progresspercentage; } } } |