c# - Prevent using Dispatcher.Invoke in WPF code -


i'm web , backend programmer nature. try avaoid making windows programs. have make wpf client.

i have background task raises event every time. (it working poller , when criteria met event raised). noob wrote code attached event update ui.

    private void isdisconnectedevent()     {             userwindow.visibility = visibility.hidden;             disconnectwindow.visibility = visibility.visible;     } 

this gives exception because not on same thread. after googling found should change code with:

    private void isdisconnectedevent()     {         dispatcher.invoke(() =>                           {                               userwindow.visibility = visibility.hidden;                               disconnectwindow.visibility = visibility.visible;                           });     } 

this works, not event , makes code horrible ugly. there better ways this?

regarding this:

this works, not event , makes code horrible ugly

yes, wpf-based code extremely horrible unless understand , embrace the wpf mentality.

basically, interactions between custom logic (aka business logic or application logic) , wpf ui should manifest in form of declarative databinding opposed traditional imperative approach.

this means there should nothing this:

userwindow.visibility = visibility.hidden; 

anywhere in code, because introducing things makes code dependent on ui , executable on ui thread.

instead, wpf approach declaratively databind visibility propety of ui element (in xaml) relevant bool property can operate outside, this:

<userwindow visibility="{binding showuserwindow, converter={my:booltovisibilityconverter}}">    <!-- ... --> </userwindow> 

then, need create relevant class contains properties ui expecting bind to. called viewmodel.

notice in order support two-way wpf databinding, viewmodels must implement inotifypropertychanged interface.

when doing so, convenient have propertychanged event interface marshalled ui thread, no longer have worry setting viewmodel's properties using dispatcher.

therefore our first step have our viewmodels inherit class this:

(taken this answer):

public class propertychangedbase:inotifypropertychanged {     public event propertychangedeventhandler propertychanged;      protected virtual void onpropertychanged(string propertyname)     {         //raise propertychanged event on ui thread, relevant propertyname parameter:         application.current.dispatcher.begininvoke((action) (() =>         {             propertychangedeventhandler handler = propertychanged;             if (handler != null) handler(this, new propertychangedeventargs(propertyname));         }));     } } 

once have our property change notification dispatch ui thread in place, can proceed create relevant viewmodel suits, in case, userwindow , it's databinding expectations:

public class userviewmodel: propertychangedbase {     private bool _showuserwindow;     public bool showuserwindow     {         {return _showuserwindow; }         set         {             _showuserwindow = value;             onpropertychanged("showuserwindow"); //this important!!!         }     } } 

finally, need set window's datacontext instance of it's corresponding viewmodel. 1 simple way in window's constructor:

public userwindow() //window's constructor {     initializecomponent();  //this required.      datacontext = new userviewmodel(); //here set datacontext } 

as can see in example, there literally no need manipulate ui element's properties in procedural code. not because resolves thread affinity issues (because can set showuserwindow property thread), because makes viewmodels , logic decoupled ui , testable , more scalable.

this same concept applies in wpf.

one detail need mention i'm making use of technique of combining markupextension , ivalueconverter in order reduce the xaml boilerplate involved in using converters.

you can read more in link , msdn databinding page linked above.

let me know if need further details.


Comments

Popular posts from this blog

OpenCV OpenCL: Convert Mat to Bitmap in JNI Layer for Android -

android - org.xmlpull.v1.XmlPullParserException: expected: START_TAG {http://schemas.xmlsoap.org/soap/envelope/}Envelope -

python - How to remove the Xframe Options header in django? -