datagrid - WPF troubles hooking CollectionChanged events -


i have datagrid need calculate total of price column of nested datagrid, so:

image

i'm trying follow this example items observable collection each person object gets notified on changes. difference i'm implementing inside class, not view model.

public class person : notifyobject     {         private observablecollection<item> _items;         public observablecollection<item> items         {             { return _items; }             set { _items = value; onpropertychanged("items"); }         }         private string _name;         public string name         {             { return _name; }             set { _name = value; onpropertychanged("name"); }         }         public double total         {             { return items.sum(i => i.price); }             set { onpropertychanged("total"); }         }          public person()         {             console.writeline("0001 constructor");             this.items = new observablecollection<item>();             this.items.collectionchanged += items_collectionchanged;             this.items.add(new item());         }         private void items_collectionchanged(object sender, notifycollectionchangedeventargs e)         {             console.writeline("0002 collectionchanged");             if (e.newitems != null)                 foreach (item item in e.newitems)                     item.propertychanged += items_propertychanged;              if (e.olditems != null)                 foreach (item item in e.olditems)                     item.propertychanged -= items_propertychanged;         }          private void items_propertychanged(object sender, propertychangedeventargs e)         {             console.writeline("0003 propertychanged");             this.total = items.sum(i => i.price);         }     } 

the code inside constructor doesn't hook events when new item initialized or existing 1 has been edited. therefore, items_propertychanged event never fires. can refresh entire list manually. doing wrong here?

or maybe there's different approach calculate total each person's purchase list?

below entire code if cares @ it.

xaml

<window x:class="collection_changed_2.mainwindow"         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"         xmlns:local="clr-namespace:collection_changed_2"         mc:ignorable="d"         title="mainwindow" sizetocontent="height" width="525">     <grid>         <grid.rowdefinitions>             <rowdefinition height="auto"/>             <rowdefinition />         </grid.rowdefinitions>         <datagrid x:name="datagrid1"                   grid.row="0"                   itemssource="{binding datacollection}"                   selecteditem="{binding datacollectionselecteditem}"                   autogeneratecolumns="false"                    canuseraddrows="false" >             <datagrid.columns>                 <datagridtextcolumn header="name" binding="{binding name}" width="2*"/>                 <datagridtemplatecolumn header="item/price" width="3*">                     <datagridtemplatecolumn.celltemplate >                         <datatemplate>                             <datagrid x:name="datagriditem"                                        itemssource="{binding items}"                                       selecteditem="{binding relativesource={relativesource findancestor, ancestortype={x:type window}}, path=datacontext.itemsselecteditem}"                                       background="transparent"                                       headersvisibility="none"                                       autogeneratecolumns="false"                                       canuseraddrows="false" >                                 <datagrid.columns>                                     <datagridtextcolumn binding="{binding itemname}" width="*"/>                                     <datagridtextcolumn binding="{binding price}" width="50"/>                                     <datagridtemplatecolumn header="button" width="auto">                                         <datagridtemplatecolumn.celltemplate>                                             <datatemplate>                                                 <stackpanel>                                                     <button  content="+"                                                              command="{binding relativesource={relativesource findancestor, ancestortype={x:type window}}, path=datacontext.additem }"                                                              width="20" height="20">                                                     </button>                                                 </stackpanel>                                             </datatemplate>                                         </datagridtemplatecolumn.celltemplate>                                     </datagridtemplatecolumn>                                 </datagrid.columns>                             </datagrid>                         </datatemplate>                     </datagridtemplatecolumn.celltemplate>                 </datagridtemplatecolumn>                 <datagridtextcolumn header="total" binding="{binding total, mode=twoway, updatesourcetrigger=propertychanged}" width="auto"/>                 <datagridtemplatecolumn header="buttons" width="auto">                     <datagridtemplatecolumn.celltemplate>                         <datatemplate>                             <stackpanel verticalalignment="center">                                 <button  command="{binding relativesource={relativesource findancestor, ancestortype={x:type window}}, path=datacontext.addperson}" width="20" height="20">+</button>                             </stackpanel>                         </datatemplate>                     </datagridtemplatecolumn.celltemplate>                 </datagridtemplatecolumn>             </datagrid.columns>         </datagrid>         <stackpanel grid.row="1" margin="10">             <button  width="150" height="30"  content="refresh" command="{binding refresh}" />         </stackpanel>     </grid> </window> 

c#

using system; using system.collections.objectmodel; using system.collections.specialized; using system.componentmodel; using system.linq; using system.windows; using system.windows.data; using system.windows.input;  namespace collection_changed_2 {     public class item : notifyobject     {         private string _itemname;         public string itemname         {             { return _itemname; }             set { _itemname = value; onpropertychanged("itemname"); }         }         private double _price;         public double price         {             { return _price; }             set { _price = value; onpropertychanged("price"); }         }     }      public class person : notifyobject     {         private observablecollection<item> _items;         public observablecollection<item> items         {             { return _items; }             set { _items = value; onpropertychanged("items"); }         }         private string _name;         public string name         {             { return _name; }             set { _name = value; onpropertychanged("name"); }         }         public double total         {             { return items.sum(i => i.price); }             set { onpropertychanged("total"); }         }          public person()         {             console.writeline("0001 constructor");             this.items = new observablecollection<item>();             this.items.collectionchanged += items_collectionchanged;             this.items.add(new item());         }         private void items_collectionchanged(object sender, notifycollectionchangedeventargs e)         {             console.writeline("0002 collectionchanged");             if (e.newitems != null)                 foreach (item item in e.newitems)                     item.propertychanged += items_propertychanged;              if (e.olditems != null)                 foreach (item item in e.olditems)                     item.propertychanged -= items_propertychanged;         }          private void items_propertychanged(object sender, propertychangedeventargs e)         {             console.writeline("0003 propertychanged");             this.total = items.sum(i => i.price);         }     }      public abstract class notifyobject : inotifypropertychanged     {         public event propertychangedeventhandler propertychanged;         protected void onpropertychanged(string property)         {             if (propertychanged != null)                 propertychanged(this, new propertychangedeventargs(property));         }     }      public class relaycommand : icommand     {         private action<object> executedelegate;         readonly predicate<object> canexecutedelegate;          public relaycommand(action<object> execute, predicate<object> canexecute)         {             if (execute == null)                 throw new nullreferenceexception("execute");             executedelegate = execute;             canexecutedelegate = canexecute;         }          public relaycommand(action<object> execute) : this(execute, null) { }          public event eventhandler canexecutechanged         {             add { commandmanager.requerysuggested += value; }             remove { commandmanager.requerysuggested -= value; }         }          public bool canexecute(object parameter)         {             return canexecutedelegate == null ? true : canexecutedelegate(parameter);         }          public void execute(object parameter)         {             executedelegate.invoke(parameter);         }     }      public class viewmodel : notifyobject     {         public observablecollection<person> datacollection { get; set; }          public person datacollectionselecteditem { get; set; }         public item itemsselecteditem { get; set; }          public relaycommand addperson { get; private set; }         public relaycommand additem { get; private set; }         public relaycommand refresh { get; private set; }          public viewmodel()         {             datacollection = new observablecollection<person>             {                 new person() {                     name = "friedrich nietzsche",                     items = new observablecollection<item> {                         new item { itemname = "phone", price = 220 },                         new item { itemname = "tablet", price = 350 },                     }                 },                 new person() {                     name = "jean baudrillard",                     items = new observablecollection<item> {                         new item { itemname = "teddy bear deluxe", price = 2200 },                         new item { itemname = "pokemon", price = 100 }                     }                  }             };              additem = new relaycommand(additemcode, null);             addperson = new relaycommand(addpersoncode, null);             refresh = new relaycommand(refreshcode, null);         }          public void additemcode(object parameter)         {             var collectionindex = datacollection.indexof(datacollectionselecteditem);             var itemindex = datacollection[collectionindex].items.indexof(itemsselecteditem);             item newitem = new item() { itemname = "item_name", price = 100 };             datacollection[collectionindex].items.insert(itemindex + 1, newitem);         }         public void addpersoncode(object parameter)         {             var collectionindex = datacollection.indexof(datacollectionselecteditem);             person newlist = new person()             {                 name = "new_name",                 items = new observablecollection<item>() { new item() { itemname = "item_name", price = 100 } }             };             datacollection.insert(collectionindex + 1, newlist);         }         private void refreshcode(object parameter)         {             collectionviewsource.getdefaultview(datacollection).refresh();         }     }      public partial class mainwindow : window     {         public mainwindow()         {             initializecomponent();             this.datacontext = new viewmodel();         }     } } 

do not use eventhandlers between viewmodels - black magic , can bring u memory leaks, because of created references.

public interface iupdatesum {     void updatesum(); }   public class person : iupdatesum {      /* ... */      public void updatesum()     {         this.total = items.sum(i => i.price);     }       /* ... */ }   public class item {     private iupdatesum sumupdate;      private double price;      public item(iupdatesum sumupdate)     {         sumupdate = sumupdate;     }      public double price     {                 {             return price;         }         set         {             raisepropertychanged("price");             sumupdate.updatesum();         }     } } 

i know not beautiful works


Comments

Popular posts from this blog

javascript - Clear button on addentry page doesn't work -

c# - Selenium Authentication Popup preventing driver close or quit -

tensorflow when input_data MNIST_data , zlib.error: Error -3 while decompressing: invalid block type -