Multi-threaded programming (4): multithreading and UI operations

Source: Internet
Author: User

To allow the program to respond to user operations as soon as possible, the thread is often used when developing Windows applications. If a thread is not used for time-consuming operations, the UI interface will be stuck for a long time. In this case, the user is reluctant to see it, in this case, we want to use threads to solve this problem.
The following code uses the UI for multi-threaded operations:

Using system; <br/> using system. collections. generic; <br/> using system. componentmodel; <br/> using system. data; <br/> using system. drawing; <br/> using system. text; <br/> using system. windows. forms; <br/> using system. threading; </P> <p> namespace threadpooldemo <br/> {<br/> Public partial class threadform: Form <br/>{< br/> Public threadform () <br/>{< br/> initializecomponent (); <br/>}</P> <p> private void btnthread_click (Object sender, eventargs E) <br/>{< br/> thread = new thread (New threadstart (run); <br/> thread. start (); <br/>}</P> <p> private void run () <br/>{< br/> while (progressbar. value <progressbar. maximum) <br/>{< br/> progressbar. required mstep (); <br/>}< br/>}

The program interface is as follows:
 
The intention is to click the "Start" button to start a simulated operation and display the overall progress of the operation in the progress bar. However, if we really click the "Start" button, it will disappoint because it will throw a system. invalidoperationexception exception. The exception description is "Inter-thread operation is invalid: It is accessed by a thread that does not create the control 'ssssbar."
Checkforillegalcrossthreadcils attribute
This is because.. Net does not allow the use of threads in the debugging environment to access the UI control created by itself, this may be caused by unpredictable operations on interface controls in a multi-threaded environment. If developers can confirm that their code operation interfaces will not be faulty, A simple solution is to set the static attribute checkforillegalcrossthreadcils. The default value is true. If it is set to false, in the future, the operation interface will not throw an exception in the multi-threaded environment. The above code can be modified:

Using system; <br/> using system. collections. generic; <br/> using system. componentmodel; <br/> using system. data; <br/> using system. drawing; <br/> using system. LINQ; <br/> using system. text; <br/> using system. windows. forms; <br/> using system. threading; </P> <p> namespace threadpooldemo <br/> {<br/> Public partial class threadform: Form <br/>{< br/> Public threadform () <br/>{< br/> initializecomponent (); <br/>}</P> <p> private void btnthread_click (Object sender, eventargs E) <br/>{< br/> // indicates whether to call the wrong thread, that is, whether to allow access to the thread outside the thread where the UI is created <br/> checkforillegalcrossthreadcils = false; <br/> thread = new thread (New threadstart (run); <br/> thread. start (); <br/>}</P> <p> private void run () <br/>{< br/> while (progressbar. value <progressbar. maximum) <br/>{< br/> progressbar. required mstep (); <br/>}< br/>}

In this way, the program will not throw an exception.

However, we may still be confused when using the above Code. After all, direct interface operations are not allowed in the process, so we can also use the invoke method.

Invoke method to operate the interface
The following is an example:

Using system; <br/> using system. collections. generic; <br/> using system. componentmodel; <br/> using system. data; <br/> using system. drawing; <br/> using system. LINQ; <br/> using system. text; <br/> using system. windows. forms; <br/> using system. threading; </P> <p> namespace threadpooldemo <br/> {<br/> Public partial class threadform: form <br/>{< br/> // defines delegate for invoke use <br/> private delegate void setprogressbarvalue (INT value); <br/> Public threadform () <br/>{< br/> initializecomponent (); <br/>}</P> <p> private void btnthread_click (Object sender, eventargs E) <br/>{< br/> progressbar. value = 0; <br/> // indicates whether to call the wrong thread, that is, whether to allow access to the thread outside the thread where the UI is created <br/> // checkforillegalcrossthreadcils = false; <br/> thread = new thread (New threadstart (run); <br/> thread. start (); <br/>}< br/> // use a thread to directly set the progress bar <br/> private void run () <br/>{< br/> while (progressbar. value <progressbar. maximum) <br/>{< br/> progressbar. extends mstep (); <br/>}</P> <p> private void btninvoke_click (Object sender, eventargs E) <br/>{< br/> progressbar. value = 0; <br/> thread = new thread (New threadstart (runwithinvoke); <br/> thread. start (); <br/>}< br/> // use the invoke method to set the progress bar <br/> private void runwithinvoke () <br/>{< br/> int value = progressbar. value; <br/> while (value <progressbar. maximum) <br/>{< br/> // if it is called across threads <br/> If (invokerequired) <br/>{< br/> This. invoke (New setprogressbarvalue (setprogressvalue), value ++); <br/>}< br/> else <br/>{< br/> progressbar. value = ++ value; <br/>}< br/> // method that matches the setprogressbarvalue DeleGate <br/> private void setprogressvalue (INT value) <br/>{< br/> progressbar. value = value; <br/>}< br/>}

The functions of this method are the same as those of the preceding operations, except that you do not need to set the checkforillegalcrossthreadcils attribute and do not throw an exception. Of course, in addition to the above method, you can also use the backgroundworker class to perform the same function.

Backgroundworker Interface
The example of using the backgroundworker class to operate the UI has already been shown on Zhou Gong's blog. Therefore, the example code annotations here are relatively simple. You can refer to the examples earlier than Zhou Gong, the sample code used this time is as follows:

Using system; <br/> using system. collections. generic; <br/> using system. componentmodel; <br/> using system. data; <br/> using system. drawing; <br/> using system. LINQ; <br/> using system. text; <br/> using system. windows. forms; <br/> using system. threading; </P> <p> namespace threadpooldemo <br/> {<br/> Public partial class threadform: form <br/>{< br/> // defines delegate for invoke use <br/> private delegate void setprogressbarvalue (INT value); <br/> private backgroundworker worker; <br/> Public threadform () <br/>{< br/> initializecomponent (); <br/>}</P> <p> private void btnthread_click (Object sender, eventargs e) <br/>{< br/> progressbar. value = 0; <br/> // indicates whether to call the wrong thread, that is, whether to allow access to the thread outside the thread where the UI is created <br/> // checkforillegalcrossthreadcils = false; <br/> thread = new thread (New threadstart (run); <br/> thread. start (); <br/>}< br/> // use a thread to directly set the progress bar <br/> private void run () <br/>{< br/> while (progressbar. value <progressbar. maximum) <br/>{< br/> progressbar. extends mstep (); <br/>}</P> <p> private void btninvoke_click (Object sender, eventargs E) <br/>{< br/> progressbar. value = 0; <br/> thread = new thread (New threadstart (runwithinvoke); <br/> thread. start (); <br/>}< br/> // use the invoke method to set the progress bar <br/> private void runwithinvoke () <br/>{< br/> int value = progressbar. value; <br/> while (value <progressbar. maximum) <br/>{< br/> // if it is called across threads <br/> If (invokerequired) <br/>{< br/> This. invoke (New setprogressbarvalue (setprogressvalue), value ++); <br/>}< br/> else <br/>{< br/> progressbar. value = ++ value; <br/>}< br/> // method that matches the setprogressbarvalue DeleGate <br/> private void setprogressvalue (INT value) <br/>{< br/> progressbar. value = value; <br/>}</P> <p> private void btnbackgroundworker_click (Object sender, eventargs e) <br/>{< br/> progressbar. value = 0; <br/> worker = new backgroundworker (); <br/> worker. dowork + = new doworkeventhandler (worker_dowork); <br/> // worker that is executed when the work progress changes <br/>. progresschanged + = new progresschangedeventhandler (worker_progresschanged); <br/> // method executed after the event is processed <br/> worker. runworkercompleted + = new runworkercompletedeventhandler (worker_runworkercompleted); <br/> worker. workerreportsprogress = true; // supports reporting progress updates <br/> worker. workersuppscanscancellation = false; // asynchronous cancellation is not supported <br/> worker. runworkerasync (); // start the execution <br/> btnbackgroundworker. enabled = false; <br/>}< br/> // method executed after the event is processed <br/> void worker_runworkercompleted (Object sender, runworkercompletedeventargs E) <br/>{< br/> btnbackgroundworker. enabled = true; <br/>}< br/> // event handling method when the work progress changes <br/> void worker_progresschanged (Object sender, progresschangedeventargs E) <br/>{< br/> // you can communicate with the interface in this method <br/> progressbar. value = E. progresspercentage; <br/>}< br/> // event handling method executed when the job starts <br/> void worker_dowork (Object sender, doworkeventargs E) <br/>{< br/> int value = progressbar. value; <br/> while (value <progressbar. maximum) <br/>{< br/> worker. reportprogress (++ value); // report progress <br/>}< br/>}

Of course, in addition to backgroundworker, you can use the system. Windows. Forms. Timer class to complete the above functions. The Code is as follows:

Using system; <br/> using system. collections. generic; <br/> using system. componentmodel; <br/> using system. data; <br/> using system. drawing; <br/> using system. LINQ; <br/> using system. text; <br/> using system. windows. forms; <br/> using system. threading; </P> <p> namespace threadpooldemo <br/> {<br/> Public partial class threadform: form <br/>{< br/> // defines delegate for invoke use <br/> private delegate void setprogressbarvalue (INT value); <br/> private backgroundworker worker; <br/> Public threadform () <br/>{< br/> initializecomponent (); <br/>}</P> <p> private void btnthread_click (Object sender, eventargs e) <br/>{< br/> progressbar. value = 0; <br/> // indicates whether to call the wrong thread, that is, whether to allow access to the thread outside the thread where the UI is created <br/> // checkforillegalcrossthreadcils = false; <br/> thread = new thread (New threadstart (run); <br/> thread. start (); <br/>}< br/> // use a thread to directly set the progress bar <br/> private void run () <br/>{< br/> while (progressbar. value <progressbar. maximum) <br/>{< br/> progressbar. extends mstep (); <br/>}</P> <p> private void btninvoke_click (Object sender, eventargs E) <br/>{< br/> progressbar. value = 0; <br/> thread = new thread (New threadstart (runwithinvoke); <br/> thread. start (); <br/>}< br/> // use the invoke method to set the progress bar <br/> private void runwithinvoke () <br/>{< br/> int value = progressbar. value; <br/> while (value <progressbar. maximum) <br/>{< br/> // if it is called across threads <br/> If (invokerequired) <br/>{< br/> This. invoke (New setprogressbarvalue (setprogressvalue), value ++); <br/>}< br/> else <br/>{< br/> progressbar. value = ++ value; <br/>}< br/> // method that matches the setprogressbarvalue DeleGate <br/> private void setprogressvalue (INT value) <br/>{< br/> progressbar. value = value; <br/>}</P> <p> private void btnbackgroundworker_click (Object sender, eventargs e) <br/>{< br/> progressbar. value = 0; <br/> worker = new backgroundworker (); <br/> worker. dowork + = new doworkeventhandler (worker_dowork); <br/> // worker that is executed when the work progress changes <br/>. progresschanged + = new progresschangedeventhandler (worker_progresschanged); <br/> // method executed after the event is processed <br/> worker. runworkercompleted + = new runworkercompletedeventhandler (worker_runworkercompleted); <br/> worker. workerreportsprogress = true; // supports reporting progress updates <br/> worker. workersuppscanscancellation = false; // asynchronous cancellation is not supported <br/> worker. runworkerasync (); // start the execution <br/> btnbackgroundworker. enabled = false; <br/>}< br/> // method executed after the event is processed <br/> void worker_runworkercompleted (Object sender, runworkercompletedeventargs E) <br/>{< br/> btnbackgroundworker. enabled = true; <br/>}< br/> // event handling method when the work progress changes <br/> void worker_progresschanged (Object sender, progresschangedeventargs E) <br/>{< br/> // you can communicate with the interface in this method <br/> progressbar. value = E. progresspercentage; <br/>}< br/> // event handling method executed when the job starts <br/> void worker_dowork (Object sender, doworkeventargs E) <br/>{< br/> int value = progressbar. value; <br/> while (value <progressbar. maximum) <br/>{< br/> worker. reportprogress (++ value); // report progress <br/>}< br/> // use system. windows. forms. timer to operate on the Interface <br/> private void btntimer_click (Object sender, eventargs e) <br/>{< br/> progressbar. value = 0; <br/> // note that.. Net has multiple namespaces With Timer classes. To facilitate the differences, the namespace format is used. <br/> system. windows. forms. timer timer = new system. windows. forms. timer (); <br/> timer. interval = 1; <br/> timer. tick + = new eventhandler (timer_tick); <br/> timer. enabled = true; <br/>}< br/> // method to be periodically executed in timer <br/> void timer_tick (Object sender, eventargs E) <br/>{< br/> int value = progressbar. value; <br/> If (value <progressbar. maximum) <br/>{< br/> progressbar. value = value + 100; <br/>}< br/>}

Summary: This article describes how to use a thread to operate the windows application interface. These methods can be used for reference when writing a multi-threaded UI program.

Zhou Gong
2010-01-11

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.