c# - Sorting second level of TreeView and seeing changes... possible? -
this first post here, have been trying few techniques found in other questions can't seem working want... making changes existing application (.net 3.5 wpf , c#, , entity framework sqlserver2008). new both efdm , wpf. new version needs compatible existing databases previous version, without modification existing databases, quite reluctant changing datamodel , objects generated it.
anyway, here's question: have objects "staffincentive" , "staffincentivelines" edm, each staffincentive having 0 many staffincentiveline attached. display treeview, , need able dynamically add or remove staffincentiveline.
<treeview itemssource="{binding}" name="maintree"> <treeview.itemtemplate> <hierarchicaldatatemplate itemssource="{binding staffincentiveline}"> <textbox text="{binding name}"/> <button tag="{binding}" click="addline" content="add line" /> <hierarchicaldatatemplate.itemtemplate> <datatemplate > <textbox text="{binding lbound}"/> <textbox text="{binding percentage}"/> <button tag="{binding}" click="delline" content="remove"/> </datatemplate> </hierarchicaldatatemplate.itemtemplate> </hierarchicaldatatemplate> </treeview.itemtemplate> </treeview>
this works fine, staffincentivelines not sorted, need appear in order (ascending lbound). have looked solution , found converter
public object convert(object value, type targettype, object parameter, system.globalization.cultureinfo culture) {return ((entitycollection<staffincentiveline>)value).orderby(o => o.lbound);}
then realised when add or remove staffincentiveline using buttons on screen, changes not display. if understand corrently it's because incentivelines displayed through view provided sort converter, , view not refreshed when changes made collection. if understand correctly again, because entitycollection doesn't implement inotifypropertychanged. if refresh view using
collectionviewsource.getdefaultview(_incentives).refresh(); treeview gets refreshed , items collapsed quite confusing user...
so how can have both sorting , refreshing working without changing object classes staffincentive , staffincentiveline? should create class includes them , implement inotifypropertychanged?
thanks
i managed :)
i have created 2 classes staffincentivehelperobject , staffincentivelinehelperobject implement inotifypropertychanged. overlap existing classes , fire events when changes made through accessers. can there methods add/remove staffincentivelinehelperobject observablecollection in staffincentivehelperobject , , these methods add/remove original object edm... bit links changes made view database.
public class staffincentivehelperobject : inotifypropertychanged// { public delegate void collectionchangeddelegate(); public static collectionchangeddelegate collectionchanged; public staffincentivehelperobject(staffincentive input) { this._staffincentive = input; } private staffincentive _staffincentive; public staffincentive staffincentive { { return _staffincentive; } set { if (_staffincentive == value) return; _staffincentive = value; onpropertychanged("staffincentive"); } } public decimal? staffincentiveincrement { { return _staffincentive.increment; } set { if (_staffincentive.increment != value) { _staffincentive.increment = value; onpropertychanged("staffincentive"); } } } public string staffincentivename { { return _staffincentive.name; } set { if (_staffincentive.name != value) { _staffincentive.name = value; onpropertychanged("staffincentive"); } } } public byte? staffincentivetype { { return _staffincentive.type; } set { if(_staffincentive.type != value) { _staffincentive.type = value; onpropertychanged("staffincentive"); } } } private observablecollection<staffincentivelinehelperobject> _staffincentivelines = new observablecollection<staffincentivelinehelperobject>(); public observablecollection<staffincentivelinehelperobject> staffincentivelines { { return _staffincentivelines; } set { _staffincentivelines = value; onpropertychanged("staffincentivelines"); } } public void addstaffincentiveline( staffincentiveline sil) { sil.staffincentive = this._staffincentive; _staffincentive.staffincentiveline.add(sil); staffincentivelines.add(new staffincentivelinehelperobject(sil, this)); //onpropertychanged("staffincentiveline"); if (collectionchanged != null) { collectionchanged.invoke(); } } public void removestaffincentiveline(staffincentivelinehelperobject silho) { _staffincentive.staffincentiveline.remove(silho.staffincentiveline); _staffincentivelines.remove(silho); //onpropertychanged("staffincentiveline"); if (collectionchanged != null) { collectionchanged.invoke(); } } #region inotifypropertychanged members public event propertychangedeventhandler propertychanged; private void onpropertychanged(string name) { var x = propertychanged; if (x != null) x(this, new propertychangedeventargs(name)); } #endregion } public class staffincentivelinehelperobject : inotifypropertychanged//, inotifyco { public staffincentivelinehelperobject(staffincentiveline input, staffincentivehelperobject parent) { this._staffincentiveline = input; this.parent = parent; } public staffincentivehelperobject parent { get; set;} private staffincentiveline _staffincentiveline; public staffincentiveline staffincentiveline { { return _staffincentiveline; } set { if (_staffincentiveline == value) return; _staffincentiveline = value; onpropertychanged("staffincentiveline"); } } public decimal? staffincentivelinelbound { { return _staffincentiveline.lbound; } set { if (_staffincentiveline.lbound != value) { _staffincentiveline.lbound = value; onpropertychanged("staffincentiveline"); } } } public double? staffincentivelinepercentage { { return _staffincentiveline.percentage; } set { if (_staffincentiveline.percentage != value) { _staffincentiveline.percentage = value; onpropertychanged("staffincentiveline"); } } } #region inotifypropertychanged members public event propertychangedeventhandler propertychanged; private void onpropertychanged(string name) { var x = propertychanged; if (x != null) x(this, new propertychangedeventargs(name)); } #endregion }
the datacontext of xaml set observablecollection built existing objects of edm this
observablecollection<supportingobjects.staffincentivehelperobject> myicentives = new observablecollection<supportingobjects.staffincentivehelperobject>(); foreach (staffincentive si in db_incentives) { staffincentivehelperobject siho = new staffincentivehelperobject(si); myicentives.add(siho); foreach (staffincentiveline sil in si.staffincentiveline) { siho.addstaffincentiveline(sil); } }
then xaml displays/updates using accessers.
<treeview itemssource="{binding}" name="maintree"> <treeview.itemtemplate> <hierarchicaldatatemplate itemssource="{binding staffincentivelines, converter={staticresource incentivelinehelperobjectsort}, converterparameter=staffincentivelinelbound}"> <stackpanel orientation="horizontal" > <textbox text="{binding staffincentivename}" width="120" /> <button tag="{binding}" click="addline" content="add line" /> </stackpanel> <hierarchicaldatatemplate.itemtemplate> <datatemplate > <stackpanel orientation="horizontal" margin="150,0,0,0"> <textbox text="{binding staffincentivelinelbound, stringformat='{}{0:c}'}" width="120" /> <textbox text="{binding staffincentivelinepercentage}" width="120" /> <button tag="{binding}" click="delline" content="remove"/> </stackpanel> </datatemplate> </hierarchicaldatatemplate.itemtemplate> </hierarchicaldatatemplate> </treeview.itemtemplate>
the sorting done @ first load , not dynamically while adding lines, fine me. here's sort converter (i copied question on site)
public class incentivelinehelperobjectsort : ivalueconverter { public object convert(object value, type targettype, object parameter, system.globalization.cultureinfo culture) { system.collections.objectmodel.observablecollection<staffincentivelinehelperobject> collection = value system.collections.objectmodel.observablecollection<staffincentivelinehelperobject>; listcollectionview view = new listcollectionview(collection); system.componentmodel.sortdescription sort = new system.componentmodel.sortdescription(parameter.tostring(), system.componentmodel.listsortdirection.ascending); view.sortdescriptions.add(sort); return view; } public object convertback(object value, type targettype, object parameter, system.globalization.cultureinfo culture) { return null; } }
here's methods add or remove staffincentivelines when buttons pressed.
private void addline(object sender, routedeventargs e) { var incentive = ((sender button).tag staffincentivehelperobject); incentive.addstaffincentiveline(new staffincentiveline()); treeviewitem thistreeviewitem = maintree.itemcontainergenerator.containerfromitem(incentive) treeviewitem; thistreeviewitem.isexpanded = true; } private void delline(object sender, routedeventargs e) { var line = ((sender button).tag staffincentivelinehelperobject); staffincentivehelperobject thisincentive = line.parent; thisincentive.removestaffincentiveline(line); treeviewitem thistreeviewitem = maintree.itemcontainergenerator.containerfromitem(thisincentive) treeviewitem; if (thisincentive.staffincentivelines.count == 0) { thistreeviewitem.isexpanded = false; } }
if else has better way, or means improve this, i'd happy hear :)
Comments
Post a Comment