xaml - Binding fires on unloaded view/view-model when creating a new view -


if bind radiobutton view-model property using type converter, every time create view, setter on previous viewmodel gets called, though view unloaded , should not exist anymore. here minimum code reproduce issue:

1) define enum type:

enum enumtype {    value1,    value2, } 

2) define convereter:

public class enumtypetobooleanconverter : ivalueconverter {     public object convert(object value, type targettype, object parameter, string language) {       return true;    }    public object convertback(object value, type targettype, object parameter, string language) {       return enumtype.value1;     } } 

3) define view-model:

class viewmodel : inotifypropertychanged {     private enumtype value;      public viewmodel() {          debug.writeline(string.format("viewmodel ({0})::ctor", this.gethashcode()));     }     public enumtype value {         {             debug.writeline(string.format("viewmodel ({0})::value::get", this.gethashcode()));             return this.value;         }         set {             debug.writeline(string.format("viewmodel ({0})::value::set", this.gethashcode()));             if (this.value != value) {                 this.value = value;                 this.onpropertychanged();             }         }     }     private void onpropertychanged([callermembername] string name = null) {         if (this.propertychanged != null) {             var ea = new propertychangedeventargs(name);             this.propertychanged(this, ea);         }     }     public event propertychangedeventhandler propertychanged; } 

4) define usercontrol (view.xaml)

<usercontrol     x:class="bindingissue.view"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:local="using:bindingissue"     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"     mc:ignorable="d"     d:designheight="300"     d:designwidth="400"     x:name="root">     <usercontrol.datacontext>        <local:viewmodel x:name="viewmodel"/>    </usercontrol.datacontext>      <grid>        <scrollviewer>                   <stackpanel>               <radiobutton x:name="rdo1"                            content="value1"                            ischecked="{binding path=value, converter={staticresource enumtypetobooleanconverter}, converterparameter=value1, mode=twoway, updatesourcetrigger=propertychanged}"/>                 <button x:name="btnclose"                         click="btnclose_click"                         content="close"/>            </stackpanel>        </scrollviewer>    </grid> 

5) add code behind of view:

public view() {      debug.writeline(string.format("view ({0})::ctor", this.gethashcode()));      this.initializecomponent();      this.loaded += onloaded;      this.unloaded += onunloaded; } private void btnclose_click(object sender, routedeventargs e) {     if (this.parent popup) {         debug.writeline("closing popup...");         ((popup)this.parent).isopen = false;     } } private void onloaded(object sender, routedeventargs e) {     debug.writeline(string.format("view ({0})::loaded", this.gethashcode()));   } private void onunloaded(object sender, routedeventargs e) {     debug.writeline(string.format("view ({0})::unloaded", this.gethashcode())); } 

6) mainpage (xaml)

<grid background="{themeresource applicationpagebackgroundthemebrush}"          x:name="grid">     <button x:name="btnnewview"               click="btnnewview_click"               content="new view"               margin="4"/> </grid> 

7) add event handler mainpage

private void btnnewview_click(object sender, routedeventargs e) {     debug.writeline("opening new popup...");     view view = new view();     view.horizontalalignment = horizontalalignment.center;     view.verticalalignment = verticalalignment.center;      popup popup = new popup();     popup.child = view;     popup.horizontaloffset = 300;     popup.verticaloffset = 300;     popup.isopen = true; } 

opening , closing popups multiple times results following output (please keep track of hash codes):

opening new popup...

view (46418718)::ctor

viewmodel (59312528)::ctor

viewmodel (59312528)::value::get

view (46418718)::loaded

closing popup...

view (46418718)::unloaded

opening new popup...

view (58892413)::ctor

viewmodel (61646925)::ctor

viewmodel (61646925)::value::get

viewmodel (59312528)::value::set

view (58892413)::loaded

closing popup...

view (58892413)::unloaded

which means setter viewmodel created in unloaded view model being called little bit strange. behavior same both x:bind , binding.

i know if there explanation on behavior.

to clarify more: brand new pair of view/view-model instances created each time when new view being loaded, setter on previous instance of view-model being called. previous instance of view unloaded , should not exist @ point. (think of popup being closed each time, , there not event reference old view/view-model.)

which means setter viewmodel created in unloaded view model being called little bit strange

firstly, setter not called when view unloaded, called when loading view. can add loading event handle verify this. adding loading event code code behind of view control follows:

  this.loading += view_loading;          private void view_loading(frameworkelement sender, object args)   {       debug.writeline(string.format("view ({0})::loading", this.gethashcode()));   } 

and output be:

closing popup... view (22452836)::unloaded opening new popup... view (58892413)::ctor viewmodel (61646925)::ctor view (58892413)::loading viewmodel (61646925)::value::get viewmodel (19246503)::value::set view (58892413)::loaded 

secondly, need why setter called in scenario. 1 because set binding mode twoway. if remove property follows not see setter called since viewmodel doesn't need know changes in view.

<radiobutton x:name="rdo1"  content="value1"  ischecked="{binding path=value, converter={staticresource enumtypetobooleanconverter}, converterparameter=value1,  updatesourcetrigger=propertychanged}"/> 

more details binding mode please reference this article. reason may specific radiobutton control. radiobutton can cleared clicking radiobutton in same group, cannot cleared clicking again. when set ischecked property true, thought property value of group updated. trigger twoway binding. in scenrio, can test setting default value of ischecked false follows, , find setter not called until select rdo1 on ui. or can use control checkbox testing not call setter until ischecked value updated.

public class enumtypetobooleanconverter : ivalueconverter {     public object convert(object value, type targettype, object parameter, string language)     {         return false;     }     public object convertback(object value, type targettype, object parameter, string language)     {        return enumtype.value1;            } } 

the behavior not same if scrollviewer gets removed view behavior not same lets boolean property

for these 2 scenarios, tested on side. result same outputs above. since don't know how bind boolean property, mentioned, whether setter called depend on binding mode , whether set or update property. testing code binding boolean follows have same outputs.

view.xaml

<radiobutton x:name="rdo2"            content="boolvalue"            ischecked="{binding path=boolvalue, converter={staticresource enumtypetobooleanconverter}, converterparameter=value1, mode=twoway, updatesourcetrigger=propertychanged}"/> 

converter:

public class enumtypetobooleanconverter : ivalueconverter {     public object convert(object value, type targettype, object parameter, string language)     {         return true;     }     public object convertback(object value, type targettype, object parameter, string language)     {         //return enumtype.value1;              return true;       } } 

viewmodel;

   private bool boolvalue;    public bool boolvalue    {               {            debug.writeline(string.format("viewmodel ({0})::boolvalue::get", this.gethashcode()));            return this.boolvalue;        }        set        {            debug.writeline(string.format("viewmodel ({0})::boolvalue::set", this.gethashcode()));            if (this.boolvalue != value)            {                this.boolvalue = value;                this.onpropertychanged();            }        }    } 

Comments

Popular posts from this blog

php - How to display all orders for a single product showing the most recent first? Woocommerce -

asp.net - How to correctly use QUERY_STRING in ISAPI rewrite? -

angularjs - How restrict admin panel using in backend laravel and admin panel on angular? -