Ui update method of WPF
Caused
In the past VB6 or Windows form applications, the UI update method is usually updated only by application. doevents. In Windows form, invoke and begininvoke can be used implicitly.
In WPF, how do I update the content of the UI?
Example 1: Bad example
Of course, start with an incorrect example.
Ex1bad. XAML
<Windowx:Class="WpfApplication10.Ex1Bad" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Ex1Bad"Height="300"Width="300"> <StackPanel> <LabelName="lblMsg"Content="Nothing"/> <ButtonContent="Start"Name="btnStart"Click="btnStart_Click"/> </StackPanel></Window>
Ex1bad. XAML. CS
Usingsystem. threading; usingsystem. windows; namespacewpfapplication10 {publicpartial class ex1bad: window {publicex1bad () {initializecomponent ();} privatevoid btnstart_click (objectsender, routedeventargs e) {lblmsg. content = "starting... "; thread. sleep (3000); // runs lblmsg for a long time. content = "doing... "; thread. sleep (3000); // runs lblmsg for a long time. content = "finished... ";}}}
Here, thread. Sleep (3000) is used to let the UI thread sleep for three seconds, to simulate a long period of work.
This is a common program, but it is useless. Application. doevents () can be called in Windows form APIs. WPF
Is there any similarity in?
Example 2: doevents using Windows form
Originally, no similar API can be called in WPF, but you can still directly call application. doevents. Of course, you need to reference system. Windows. Forms. dll.
Ex2winformdoevents. XAML
Usingsystem. threading; usingsystem. windows; usingswf = system. windows. forms; namespacewpfapplication10 {publicpartial class ex2winformdoevents: window {partition () {initializecomponent ();} privatevoid btnstart_click (objectsender, routedeventargs e) {lblmsg. content = "starting... "; SwF. application. doevents (); thread. sleep (3000); // runs lblmsg for a long time. content = "doing... "; SwF. application. doevents (); thread. sleep (3000); // runs lblmsg for a long time. content = "finished... ";}}}
After updating the UI, call SWF. application. doevents () to update the UI. This method is similar to the previous VB6 method. Example 3: WPF doevents
Oh? Does WPF support doevents and can only call APIs of legacy Windows Forms? No. Sample is included in the dispacherframe article.
Ex3wpfdoevents. XAML. CS
Usingsystem; usingsystem. security. permissions; usingsystem. threading; usingsystem. windows; usingsystem. windows. threading; namespacewpfapplication10 {publicpartial class ex3wpfdoevents: window {initialize () {initializecomponent ();} privatevoid btnstart_click (objectsender, routedeventargs e) {lblmsg. content = "starting... "; doevents (); thread. sleep (3000); // runs lblmsg for a long time. content = "doing... "; doevents (); thread. sleep (3000); // runs lblmsg for a long time. content = "finished... ";} [securitypermissionattribute (securityaction. demand, flags = securitypermissionflag. unmanagedcode)] publicvoid doevents () {var frame = newdispatcherframe (); dispatcher. currentdispatcher. begininvoke (dispatcherpriority. background, newdispatcheroperationcallback (exitframe), frame); dispatcher. pushframe (FRAME);} publicobject exitframe (objectf) {(dispatcherframe) F ). continue = false; returnnull;} publicstatic void doevents2 () {Action action = delegate {}; dispatcher. currentdispatcher. invoke (dispatcherpriority. input, Action );}}}
Doevents () and doevents2 () have the same effect. Doevents is edevil
Doevents is so easy to use, why does WPF still need to specify dispatcher, or
What about the windows form begininvoke APIs?
Run the following program.
privatevoid btnEvil_Click(objectsender, RoutedEventArgs e){ for(inti = 0; i < 10000000; i++) { System.Windows.Forms.Application.DoEvents(); } MessageBox.Show("Ok");}
During peak hours, I remember opening a staff member to check the CPU quota, so it will take a long time to complete. Although the UI does not have any updates, why does the CPU increase?
The principle of doevent is execution loop, which is to check whether there is a message to be updated in the form of a partial loop ). When you see the circle, you will know what is going on.
The doevents of WPF in Example 3 is the same.
Example 4: backgroundworker
Is there a normal way to update the UI? Let's take a look at the design method of ex1bad. XAML. CS. After updating the lblmessage, you can perform a synchronization operation. Working on the UI thread will cause the UI to stop and the user will feel helpless.
The correct method is to use the backgroundworker to renew the work for a long time and update it in Non-synchronous mode.
Ui content on the UI tread.
Ex4backgroundworker. XAML. CS
Usingsystem. componentmodel; usingsystem. threading; usingsystem. windows; usingsystem. windows. controls; namespacewpfapplication10 {publicpartial class values: window {values () {initializecomponent ();} privatevoid btnstart_click (objectsender, routedeventargs e) {values (lblmsg, "starting "); trim (lblmsg, "doing"); executelongtimework (lblmsg, "finished");} privatevoid trim (label Label, stringmessage) {var backgroundworker = newbackgroundworker (); backgroundworker. dowork + = (S, O) =>{ thread. sleep (3000); // keep working for a long time}; backgroundworker. runworkercompleted + = (S, argS) => {dispatcher. begininvoke (newaction () => {label. content = message;}) ;}; backgroundworker. runworkerasync ();}}}
Backgroundworker is used to create a new
Thread to upload the dowork event handler. After the finished row is finished, the runworkercompleted event handler will be merged. Therefore, we need to update the UI in the event handler of runworkercompleted.
Use dispatcher to update the UI.
UI. Basically, dispatcher is a queue concept.
Ui. WPF will update the UI in the reverse order of dispatcherpriority.
Conclusion
Although it's just a small UI update method, there are also a lot of questions!