first, Preface
Set the value of a control in a single thread simple thing, only need to set the value of the control text can be, but some business scenarios are very complex, the interface of a lot of controls, in this case, when the volume of data is more, in a single-threaded update UI will inevitably occur in the animation or Kaka phenomenon, the user experience is very uncomfortable, therefore, multiple threads must be used to process data and ui. But if you add a thread directly to update the control information, it will throw an error, obviously Microsoft does not want us to do this, because the UI control is not thread-safe, if you arbitrarily change the value of the control in any thread, there will be a variety of strange problems, multiple threads compete for resources, the Control's value is not changed in an orderly manner, Obviously this is the result we don't want to see. Of course, There are a lot of ways to solve this problem, here are a few common methods, do a record, warm and know New.
second, do not detect inter-thread conflicts
Because of the changes in the business, resulting in an increase in interface controls and data, the performance of single-threaded situations is worrying, then need to switch from single-threaded to multi-threaded, we wrote the code may be:
1 Private voidBtnsetorg_click (Objectsender, EventArgs E)2 {3Thread T =NewThread (NewParameterizedthreadstart (setorgvalue));4 //thread t = new Thread (setorgvalue);5T.start ("Organization");6 }7 8 voidSetorgvalue (ObjectObj)9 {Ten this. Org.text =obj. ToString (); one}
The code above creates a new thread and assigns a value to the ORG control in the new thread, which looks fine, but when we run it, we will report an error: the operation between threads is invalid: it is accessed from a thread that does not create a control "Org". This means that T in the above code is not a thread that creates a textbox, so you cannot access the properties of the Org Control. The Control's data can only be accessed by the thread that created the control by default, otherwise it can cause read-write inconsistencies. The operating system describes the PV operation , which is a good explanation. There is a very simple way to avoid this error, which is to not detect inter-thread collisions, just add a line of code to the Constructor:
1 publicUIForm ()2 {3 4 InitializeComponent ();5Control.checkforillegalcrossthreadcalls =false;//do not detect Cross-thread calls6 }7 8 Private voidBtnsetorg_click (Objectsender, EventArgs E)9 {TenThread T =NewThread (NewParameterizedthreadstart (setorgvalue)); one //thread t = new Thread (setorgvalue); aT.start ("Organization"); - } - the - voidSetorgvalue (ObjectObj) - { - this. Org.text =obj. ToString (); +}
This code is clearly designed to cope with invalid errors between threads, turning off the detection of Cross-thread access ui, allowing multithreading to arbitrarily change control data, But what is the value of the last Control's property, and only God knows, does not advocate using this Method.
Iii. Common multi-threaded Access UI control mode
- Invoke with Delegate
- Using BackgroundWorker
- Leveraging the SynchronizationContext context
- Using Dispatcher.begininvoke
first, the value of the UI control is updated in the way that the delegate is Called. Each control has a invokerequired property of type bool, indicating whether the control has a thread other than the one that created the control to access the control, and if a value of TRUE indicates that a thread exists, then the value of the control needs to be updated with the delegate Invocation. Change the code for the second part as Follows:
1 Delegate voidSetValue (Objectobj);2 3 Private voidBtnsetorg_click (Objectsender, EventArgs E)4 {5Thread T =NewThread (NewParameterizedthreadstart (setorgvalue));6 //thread t = new Thread (setorgvalue);7T.start ("Organization");8 }9 Ten Private voidUpdateorg (ObjectObj) one { a - if(org.invokerequired)//If a thread that is not creating the control accesses the control - { theSetValueSet=setorgvalue; -Org.invoke (Set, obj); - } - Else + { -Org.text =obj. ToString (); + } a } at - Private voidSetorgvalue (ObjectObj) - { - this. Org.text =obj. ToString (); -}
In the case of a delegate, the first thing to check is whether the thread that accesses the control is the thread that created the control, or, if it is not, a delegate to call the method that sets the Value. If you invoke a Control's method from another thread, you must use the Control's invoke method to marshal the call to the appropriate THREAD. There is an interesting metaphor on the web that if someone borrows money from you (org Control) (to access and modify it), it's not safe to go directly to your wallet (setting the Org's property value). So I need to tell you in advance that I need to borrow money (entrusted) and then borrow money (thread-safe) and lend it to the Borrower. This is easier to understand.
The second approach is to use BackgroundWorker to access the control, which essentially creates a new thread, but BackgroundWorker does a package that makes it easier for us to Use.
1 Private voidBtnsetorg_click (Objectsender, EventArgs E)2 {3 using(backgroundworker bw =NewBackgroundWorker ())4 {5Bw. RunWorkerCompleted + =NewRunworkercompletedeventhandler (runworkercompleted);6Bw. DoWork + =NewDoworkeventhandler (DoWork);7Bw. RunWorkerAsync ("Organization");8 }9 }Ten one voidRunWorkerCompleted (Objectsender, Runworkercompletedeventargs E) a { - //the background Thread is now complete and the main thread is returned, so you can use the UI control directly - this. TextBox1.Text =e.result.tostring (); theMessageBox.Show (Thread.CurrentThread.ManagedThreadId.ToString ());//View the ID of the current thread - } - - voidDoWork (Objectsender, DoWorkEventArgs E) + { -MessageBox.Show (Thread.CurrentThread.ManagedThreadId.ToString ());//View the ID of the current thread +E.result = e.argument;//This is simply to return the parameter as a result, of course, You can do complex processing here, and then return the results you want (the operation is done on another thread) a}
The third way is to take advantage of the SynchronizationContext Context. This approach is not very common compared to the above several ways. Use the following methods:
1 Private voidBtnset_click (Objectsender, EventArgs E)2 {3Thread T =NewThread (NewParameterizedthreadstart (Run));4Orgparam _org =NewOrgparam () {Context = synchronizationcontext.current, Org ="Organization" };5 T.start (_org);6 }7 voidRun (ObjectObj)8 {9orgparam org = obj asorgparam;Ten Org. Context.post (settextvalue, Org. Org); one } a - voidSettextvalue (ObjectObj) - { the this. Org.text =obj. ToString (); - } - public classOrgparam - { + publicSynchronizationContext Context {Set;Get; } - public ObjectORG {Set;Get; } +}
The last is to use Dispatcher.begininvoke to update the value of the Control. This method is relatively convenient, but it is not very common.
1 Private voidBtnsetorg_click (Objectsender, EventArgs E)2 {3Thread T =NewThread (NewParameterizedthreadstart (setorgvalue));4T.start ("orgnization");5 }6 Private voidSetorgvalue (ObjectObj)7 {8 this. Dispatcher.begininvoke (() = { thistxt. Text =Text. ToString (); }); 9}Iv. Summary
These are several ways to update control values under multiple threads, albeit in a different way, but in order to solve problems with multithreaded access Controls. The method that does not detect the conflict between threads and the way to use the delegate is limited to WinForm , and the last Dispatcher.begininvoke is limited to silverlight, while BackgroundWorker and SynchronizationContext are both suitable for winform/ Silverlight's. Before writing winform, only know to use the way of delegation and BackgroundWorker to solve the problem of cross-threading access control, now look back to this piece of content, but also know several ways to solve the problem, perhaps this is what Confucius said "warm so know new" bar. The new Year is coming soon, and I wish you all a happy!
Melodious shepherd's flute
Blog Address: http://www.cnblogs.com/xhb-bky-blog/p/6262790.html
Disclaimer: the original text of this blog only represents my work in a certain time to summarize the views or conclusions, and my unit does not have a direct interest in the Relationship. non-commercial, Unauthorized posts please retain the status quo, reproduced must retain this paragraph of the statement, and in the article page obvious location to the original Connection.
Several methods of "foundation" multithreading to update form UI