Original article: http://blog.csdn.net/cy757/archive/2009/08/22/4473980.aspx
When we use winform applications, we usually encounter the problem of using the control information on the multi-threaded control interface. However, we cannot use traditional methods to solve this problem. I will introduce it in detail below.
First, let's look at the traditional method:
Code snippet
-
- Public Partial Class Form1: Form
-
- {
-
- PublicForm1 ()
-
- {
-
- Initializecomponent ();
-
- }
- Private VoidForm1_load (ObjectSender, eventargs E)
-
- {
-
- Thread thread =NewThread (threadfuntion );
-
- Thread. isbackground =True;
-
- Thread. Start ();
-
- }
-
- Private VoidThreadfuntion ()
-
- {
- While(True)
-
- {
-
- This. Textbox1.text = datetime. Now. tostring ();
-
- Thread. Sleep (1000 );
-
- }
-
- }
-
- }
Run this sectionCodeThe system throws an exception: Cross-thread operation not valid: Control 'textbox1' accessed from a thread other than the thread it was created on. this is because. NET 2.0 and later enhanced the security mechanism, and does not allow direct cross-thread access to control attributes in winform. So how can we solve this problem? Several solutions are provided below.
In the first solution, we add the following code in the form1_load () method:
Code snippet
- private void form1_load ( Object sender, eventargs e)
- {
- control. checkforillegalcrossthreadcils = false ;
- thread = New thread (threadfuntion);
- thread. isbackground = true ;
- thread. Start ();
- }
After this code is added, we will find thatProgramIt can run normally. This code means that in this class, we do not check whether cross-thread calls are legal (if this sentence is not added, the operation is not abnormal, it indicates that the system and the default mode are not checked ). However, this method is not advisable. We can view the definition of the checkforillegalcrossthreadcils attribute and find that it is static. That is to say, no matter where the value is modified in the project, it will take effect globally. In addition, we usually check whether cross-thread access is abnormal. If someone else in the project modifies this attribute, our solution fails and we have to adopt another solution.
The second solution is to use delegate and invoke to control information from other threads. Many people write this control method on the Internet. However, I have read many such posts and it seems that there is no problem, but it has not actually solved this problem, first, let's look at the imperfect methods on the network:
Code snippet
-
- Public Partial Class Form1: Form
-
- {
- Private Delegate Void Flushclient();// Proxy
-
- PublicForm1 ()
-
- {
-
- Initializecomponent ();
-
- }
-
- Private VoidForm1_load (ObjectSender, eventargs E)
-
- {
- Thread thread =NewThread (crossthreadflush );
-
-
-
- Thread. isbackground =True;
-
- Thread. Start ();
-
- }
-
-
-
- Private VoidCrossthreadflush ()
-
- {
-
- // Bind the proxy to the Method
- FlushclientFc =New Flushclient(Threadfuntion );
-
- This. Begininvoke (FC );// Call the proxy
-
- }
-
- Private VoidThreadfuntion ()
-
- {
-
- While(True)
-
- {
- This. Textbox1.text = datetime. Now. tostring ();
-
- Thread. Sleep (1000 );
-
- }
-
- }
-
- }
In this way, we can see that the exception of cross-thread access does not exist. However, a new problem occurs and the interface does not respond. Why does this problem occur? We just need to refresh the new thread infinitely and theoretically it will not affect the main thread. Otherwise, this method is equivalent to "injecting" The New thread into the main control thread, and it achieves the control of the main thread. As long as this thread does not return, the main thread will never respond. Even if the new thread does not use an infinite loop, it can return. The use of multithreading in this way also loses its original meaning.
Now let's take a look at the recommended solution:
Code snippet
-
- Public Partial Class Form1: Form
- {
-
- Private Delegate Void Flushclient();// Proxy
-
- PublicForm1 ()
-
- {
-
- Initializecomponent ();
-
- }
-
- Private VoidForm1_load (ObjectSender, eventargs E)
-
- {
- Thread thread =NewThread (crossthreadflush );
-
- Thread. isbackground =True;
-
- Thread. Start ();
-
- }
-
-
-
- Private VoidCrossthreadflush ()
-
- {
-
- While(True)
- {
-
- // Place sleep and infinite loop outside of waiting for Asynchronization
-
- Thread. Sleep (1000 );
-
- Threadfunction ();
-
- }
-
- }
-
- Private VoidThreadfunction ()
-
- {
- If(This. Textbox1.invokerequired)// Wait for Asynchronization
-
- {
-
- FlushclientFc =New Flushclient(Threadfunction );
-
- This. Invoke (FC );// Call the refresh method through proxy
-
- }
- Else
-
- {
-
- This. Textbox1.text = datetime. Now. tostring ();
-
- }
-
- }
-
- }
After running the above code, we can see that the problem has been solved. By waiting for Asynchronization, we will not always hold the control of the main thread, in this way, you can control winform multi-threaded controls without cross-thread call exceptions.
What should I do if the function called in the thread has parameters? I will give another example.
Code snippet
- Public Delegate Void Myinvoke(StringStr );
-
-
-
- Private VoidButton9_click (ObjectSender, eventargs E)
-
- {
-
- // _ Myinvoke = new myinvoke (settext );
-
- // Checkforillegalcrossthreadcils = false;
- Thread t =NewThread (NewThreadstart (fun ));
-
- T. Start ();
-
- }
-
-
-
- Private VoidFun ()
-
- {
-
- // _ Myinvoke ("dddd ");
-
- Settext ("DDD");
-
- }
- Private VoidSettext (StringS)
-
- {
-
- If(Textbox6.invokerequired)
-
- {
-
- Myinvoke_ Myinvoke =New Myinvoke(Settext );
- This. Invoke (_ myinvoke,New Object[] {S });
-
- }
-
- Else
-
- {
-
- This. Textbox6.text = s;
-
- }
-
- }
There is also a way to do http://www.cnblogs.com/wangqiideal/archive/2008/06/07/1106136.html
Cross-thread control access solution in C # In vs2005
Recently I am working on a project and have encountered cross-thread access to page controls. however, an error is always prompted. You cannot modify the value of the control in the thread where the control is created in other threads. Later, the anonymous proxy is used, and the result is easily solved. the solution is as follows:
First, create a ListBox, lable.
Code snippet
-
- UsingSystem;
-
- UsingSystem. Collections. Generic;
-
- UsingSystem. componentmodel;
-
- UsingSystem. Data;
-
- UsingSystem. drawing;
-
- UsingSystem. text;
-
- UsingSystem. Windows. forms;
-
- UsingSystem. Threading;
-
-
- NamespaceAccesscontrol
-
- {
-
- Public Partial Class Form1:Form
-
- {
-
- PublicForm1 ()
-
- {
-
- Initializecomponent ();
-
- }
-
-
- Private VoidForm1_load (ObjectSender,EventargsE)
-
- {
-
- ThreadNewthread =New Thread(New Threadstart(Backgroundprocess ));
-
- Newthread. Start ();
-
-
-
- }
-
-
- /// <Summary>
-
- ///Define a proxy
-
- /// </Summary>
- Private Delegate Void Crossthreadoperationcontrol();
-
-
-
- Private VoidBackgroundprocess ()
-
- {
-
- // Instantiate the proxy as an anonymous proxy
- CrossthreadoperationcontrolCrossdelete =Delegate()
-
- {
-
- IntI = 1;
-
- While(I <5)
-
- {
- // Add a project to the list box
-
- Listbox1.items. Add ("Item"+ I. tostring ());
-
- I ++;
-
- }
-
- Label1.text ="I access this lable in the new thread! ";
- Listbox1.items. Add (label1.text );
-
- };
-
- Listbox1.invoke (crossdelete );
-
- }
-
-
-
- }
-
- }
I hope this tips will be helpful for your learning and work. If you have a better solution to cross-thread access control problems, I would like to share it with you.