c# - BindingProxy: binding to the indexed property -


i have bindingproxy bind visibility-property of datagridcolumns of datagrid value in dictionary ("columnsvisibility"). have context-menu, should make possible hide/show columns of grid.

<datagrid name="dgmachines"           itemssource="{binding hvmachinelist,           updatesourcetrigger=propertychanged}"                             autogeneratecolumns="false"           >     <datagrid.resources>         <local:bindingproxy x:key="proxy" data="{binding}"/>         <contextmenu x:key="datagridcolumnheadercontextmenu">             <menuitem header="names">                 <checkbox content="name" ischecked="{binding data.columnsvisibility[elementname], source={staticresource proxy}, updatesourcetrigger=propertychanged, mode=twoway}"/>             </menuitem>         </contextmenu>     </datagrid.resources>     <datagrid.columns>         <datagridtextcolumn header="name" binding="{binding elementname}" visibility="{binding data.columnsvisibility[elementname], updatesourcetrigger=propertychanged, source={staticresource proxy}, converter={staticresource booltovisibilityconv},  mode=twoway}" />                     </datagrid.columns> </datagrid> 

the initial loading works, if dictionary "columnsvisibility" filled information before initializecomponent(), value set dictionaryentry to, applied.

my target check checkbox in contextmenu , column appears/disappears. because contextmenu , columns not member of same visual tree datagrid or else, i'm using proxy. problem is, checking/unchecking of checkbox in contextmenu don't change value of columnsvisibility[elementname]. if add check/uncheck-event checkbox, can change using in code, triggering propertychanged-event don't change visual. column stays is.

is bindingproxy forwarding events gui , vice versa? seems doesn't. has idea how solve problem?

edit: bindingproxy:

public class bindingproxy : freezable {     #region overrides of freezable      protected override freezable createinstancecore()     {         return new bindingproxy();     }      #endregion      public object data     {         { return (object)getvalue(dataproperty); }         set { setvalue(dataproperty, value); }     }      // using dependencyproperty backing store data.  enables animation, styling, binding, etc...     public static readonly dependencyproperty dataproperty =         dependencyproperty.register("data", typeof(object), typeof(bindingproxy), new uipropertymetadata(null)); } 

edit2: columnsvisibilty property

private dictionary<string, bool> _columnsvisibility = new dictionary<string, bool>(); public dictionary<string, bool> columnsvisibility     {         get{return(_columnsvisibility);}         set         {                _columnsvisibility = value;              if (propertychanged != null)                 propertychanged(null, new propertychangedeventargs("columnsvisibility"));         }     } 

before initializecomponent() done on loading:

_columnsvisibility.add("elementname", false); 

edit3 ok, here full sourcecode: interaction logic:

using system.collections.generic; using system.security; using system.windows; using system.windows.controls; using system.collections.objectmodel; using system.componentmodel;  namespace hyperv { /// <summary> /// interaction logic hypervcontrol.xaml /// </summary> public partial class hypervcontrol : usercontrol, inotifypropertychanged {     public hypervcontrol()     {                     #region set default visibility columns         _columnsvisibility.add("elementname", false);         //(...)         #endregion          initializecomponent();     }      #region control triggered     private void usercontrol_loaded(object sender, routedeventargs e)     {      }      /// <summary>     /// triggered checkboxes, in contextmenu of datagrid-header show/hide columns     /// </summary>     /// <param name="sender">the checkbox, send command</param>     /// <param name="e"></param>     private void checkbox_checked(object sender, routedeventargs e)     {         //this sets value in columnsvisibility sure. value not set binding (but should...)         columnsvisibility[((checkbox)sender).tag.tostring()] = (bool)((checkbox)sender).ischecked;          //nothing of works         if (propertychanged != null)         {             propertychanged(null, new propertychangedeventargs("columnsvisibility"));             propertychanged(null, new propertychangedeventargs("columnsvisibility[machinename]"));             propertychanged(null, new propertychangedeventargs("data.columnsvisibility"));             propertychanged(null, new propertychangedeventargs("data.columnsvisibility[machinename]"));         }     }     #endregion      #region properties (private , publics)           private observablecollection<hypervmachine> _hvmachinelist;            private dictionary<string, bool> _columnsvisibility = new dictionary<string, bool>();      /// <summary>     /// contains loaded information virtual clients     /// </summary>     public observablecollection<hypervmachine> hvmachinelist     {         { return _hvmachinelist; }         set          {             _hvmachinelist = value;              if (propertychanged != null)                 propertychanged(this, new propertychangedeventargs("hvmachinelist"));         }     }      /// <summary>     /// set      /// </summary>     public dictionary<string, bool> columnsvisibility     {         get{return(_columnsvisibility);}         set         {                _columnsvisibility = value;              if (propertychanged != null)                 propertychanged(null, new propertychangedeventargs("columnsvisibility"));         }     }     #endregion      #region events     //to update content on form     public event propertychangedeventhandler propertychanged;             #endregion }  //binding proxy #region freezable context-menu-data-transmition public class bindingproxy : freezable {     #region overrides of freezable      protected override freezable createinstancecore()     {         return new bindingproxy();     }      #endregion      public object data     {         { return (object)getvalue(dataproperty); }         set { setvalue(dataproperty, value); }     }      // using dependencyproperty backing store data.  enables animation, styling, binding, etc...     public static readonly dependencyproperty dataproperty =         dependencyproperty.register("data", typeof(object), typeof(bindingproxy), new uipropertymetadata(null)); } #endregion } 

xaml:

<usercontrol xmlns:controls="clr-namespace:hyperv.controls"            x:class="hyperv.hypervcontrol"          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"           xmlns:d="http://schemas.microsoft.com/expression/blend/2008"           xmlns:local="clr-namespace:hyperv"          mc:ignorable="d"           d:designheight="300" d:designwidth="900"          loaded="usercontrol_loaded"          datacontext="{binding relativesource={relativesource mode=self}}"                       > <usercontrol.resources>     <resourcedictionary>         <resourcedictionary.mergeddictionaries>             <resourcedictionary source="language/language.xaml"/>             <resourcedictionary source="language/language.de-de.xaml"/>         </resourcedictionary.mergeddictionaries>          <local:booltovisibilityconverter x:key="booltovisibilityconv"/>     </resourcedictionary> </usercontrol.resources> <grid>     <datagrid name="dgmachines"               itemssource="{binding hvmachinelist, updatesourcetrigger=propertychanged}"               autogeneratecolumns="false"                                 >         <datagrid.resources>             <local:bindingproxy x:key="proxy" data="{binding}"/>             <contextmenu x:key="datagridcolumnheadercontextmenu">                 <menuitem header="{staticresource menheadgeneral}">                     <checkbox tag="elementname" content="{staticresource menmachinename}" ischecked="{binding data.columnsvisibility[elementname], source={staticresource proxy}, updatesourcetrigger=propertychanged, mode=twoway}" checked="checkbox_checked" unchecked="checkbox_checked"/>                                             <!-- ... -->                 </menuitem>                 <!-- ... -->             </contextmenu>              <style targettype="{x:type datagridcolumnheader}">                 <setter property="contextmenu" value="{staticresource datagridcolumnheadercontextmenu}" />             </style>           </datagrid.resources>         <datagrid.columns>             <datagridtextcolumn header="{staticresource menmachinename}" binding="{binding elementname}" visibility="{binding data.columnsvisibility[elementname], updatesourcetrigger=propertychanged, source={staticresource proxy}, converter={staticresource booltovisibilityconv},  mode=twoway}" />                             <!-- ... -->         </datagrid.columns>     </datagrid> </grid> </usercontrol> 

edit:

it error sure:

propertychanged(null, new propertychangedeventargs("columnsvisibility"));

it should be:

propertychanged(this, new propertychangedeventargs("columnsvisibility"));

i have blindly copied first edit code. well, don't see things before eyes

for future recommend use sort of function in base class like

public class notifypropertychangeablebase: inotifypropertychanged // name 'viewmodelbase' in projects, actual class control, not appropriate name {     protected void onpropertychanged(string propertyname)     {         if (this.propertychanged != null)             this.propertychanged(this,                 new propertychangedeventargs(propertyname));     }      public event propertychangedeventhandler propertychanged; } 

it did not solve issue, @ least 1 problem down

edit with(i hope) final solution:

it looks cannot notify wpf engine dictionary has changed items. , standard dictionary not on own(it not implement icollectionchanged or inotifypropertychanged).

that's why have use own dictionary, or more precise wrapper dictionary class:

public class dictionarynotificationwrapper<tkey, tvalue> : idictionary<tkey, tvalue>, inotifypropertychanged {     #region fields      private idictionary<tkey, tvalue> innerdictionary;      #endregion        #region constructors      public dictionarynotificationwrapper(idictionary<tkey, tvalue> innerdictionary)     {         if (innerdictionary == null)             throw new argumentnullexception("innerdictionary", "the inner dictionary null");          this.innerdictionary = innerdictionary;     }      #endregion        #region idictionary implementation      public tvalue this[tkey key]     {                 {             return this.innerdictionary[key];         }         set         {             this.innerdictionary[key] = value;              this.onpropertychanged("item[]");             this.onpropertychanged("count");         }     }      #endregion        #region not implemented idictionary members - free finish work      public void add(tkey key, tvalue value)     {         throw new notimplementedexception();     }      public bool containskey(tkey key)     {         throw new notimplementedexception();     }      public icollection<tkey> keys     {         { throw new notimplementedexception(); }     }      public bool remove(tkey key)     {         throw new notimplementedexception();     }      public bool trygetvalue(tkey key, out tvalue value)     {         throw new notimplementedexception();     }      public icollection<tvalue> values     {         { throw new notimplementedexception(); }     }       public void add(keyvaluepair<tkey, tvalue> item)     {         throw new notimplementedexception();     }      public void clear()     {         throw new notimplementedexception();     }      public bool contains(keyvaluepair<tkey, tvalue> item)     {         throw new notimplementedexception();     }      public void copyto(keyvaluepair<tkey, tvalue>[] array, int arrayindex)     {         throw new notimplementedexception();     }      public int count     {         { throw new notimplementedexception(); }     }      public bool isreadonly     {         { throw new notimplementedexception(); }     }      public bool remove(keyvaluepair<tkey, tvalue> item)     {         throw new notimplementedexception();     }      public ienumerator<keyvaluepair<tkey, tvalue>> getenumerator()     {         throw new notimplementedexception();     }      system.collections.ienumerator system.collections.ienumerable.getenumerator()     {         throw new notimplementedexception();     }      #endregion        #region inotifypropertychanged implementation       public event propertychangedeventhandler propertychanged;       protected void onpropertychanged(string propertyname)     {         if (this.propertychanged != null)             this.propertychanged(this,                 new propertychangedeventargs(propertyname));     }      #endregion } 

with such class:

/// <summary> /// interaction logic hypervcontrol.xaml /// </summary> public partial class hypervcontrol : usercontrol, inotifypropertychanged {     #region constructors      public hypervcontrol()     {         // form initialization         initializecomponent();          // initialize columns visibility collection         idictionary<string, boolean> innercolumnsvisibilitydictionary = new dictionary<string, boolean>();         innercolumnsvisibilitydictionary.add("elementname", true);         // wrap visibility dictionary         this.columnsvisibility = new dictionarynotificationwrapper<string, boolean>(innercolumnsvisibilitydictionary);          // initialize grid's datasource         this.hvmachinelist = new observablecollection<hypervmachine>();         this.hvmachinelist.add(new hypervmachine());         this.hvmachinelist.add(new hypervmachine());         this.hvmachinelist.add(new hypervmachine());     } 

you able notify visual components without code-behind.

p.s.: have implemented inotifyproperychanged notifies changes in item[] indexed property, try implement inotifycollectionchanged interface - unsure how work indexed bindings.
p.p.s.: haven't seen comment have found this.propertychanged(this, new ... issue.
p.p.p.s.: if have time change question title "bindingproxy: binding indexed property" better reflect problem , leave code last edit(to avoid duplication) - think of community service.


Comments

Popular posts from this blog

javascript - RequestAnimationFrame not working when exiting fullscreen switching space on Safari -

Python ctypes access violation with const pointer arguments -