wpf - Create itemscontrol multiple times with different lists -
i'm trying print 5 albums , every album print its' songs checkbox near every song. (i recommend see image published below) tried itemscontrol
don't know how every itemscontrol
bind list (with specific album's songs).
i made 5 albums within for
loop.
my problems are:
- for every album how create
itemscontrol
its' specific songs' list. - every time check
checkbox
checks checkboxes in its' row (all other albums).
here code of single itemscontrol
:
<itemscontrol grid.column="1" itemssource="{binding}" grid.issharedsizescope="true" margin="12 0 12 0"> <itemscontrol.itemtemplate> <datatemplate datatype="{x:type domain:selectableviewmodel}"> <border x:name="border" padding="8"> <grid> <grid.columndefinitions> <columndefinition sharedsizegroup="checkerz" /> <columndefinition /> </grid.columndefinitions> <checkbox verticalalignment="center" ischecked="{binding isselected}"/> <stackpanel margin="8 0 0 0" grid.column="1"> <textblock fontweight="bold" text="{binding name}" /> <textblock text="{binding description}" /> </stackpanel> </grid> </border> <datatemplate.triggers> <datatrigger binding="{binding isselected}" value="true"> <setter targetname="border" property="background" value="{dynamicresource materialdesignselection}" /> </datatrigger> </datatemplate.triggers> </datatemplate> </itemscontrol.itemtemplate> </itemscontrol>
this image of how it's looks now. (look @ red squares): click here
please me :(
try next solution:
for every album how create itemscontrol its' specific songs' list.
udate #1 - xaml code solution
<window x:class="listboxoflistboxes.mainwindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:listboxoflistboxes="clr-namespace:listboxoflistboxes" title="mainwindow" height="350" width="525"> <grid> <grid.resources> <datatemplate x:key="inneritemscontrol" datatype="{x:type listboxoflistboxes:albumviewmodel}"> <itemscontrol grid.column="1" itemssource="{binding songs}" grid.issharedsizescope="true" margin="12 0 12 0"> <itemscontrol.itemtemplate> <datatemplate datatype="{x:type listboxoflistboxes:selectableviewmodel}"> <border x:name="border" padding="8"> <grid> <grid.columndefinitions> <columndefinition sharedsizegroup="checkerz" /> <columndefinition /> </grid.columndefinitions> <checkbox verticalalignment="center" ischecked="{binding isselected}"/> <stackpanel margin="8 0 0 0" grid.column="1"> <textblock fontweight="bold" text="{binding name}" /> <textblock text="{binding description}" /> </stackpanel> </grid> </border> <datatemplate.triggers> <datatrigger binding="{binding isselected}" value="true"> <setter targetname="border" property="background" value="red" /> </datatrigger> <datatrigger binding="{binding isselected}" value="false"> <setter targetname="border" property="background" value="transparent" /> </datatrigger> </datatemplate.triggers> </datatemplate> </itemscontrol.itemtemplate> </itemscontrol> </datatemplate> <datatemplate x:key="listboxitemdatatemplate" datatype="listboxoflistboxes:albumviewmodel"> <contentcontrol content="{binding }" contenttemplate="{staticresource inneritemscontrol}"></contentcontrol> </datatemplate> </grid.resources> <grid.datacontext> <listboxoflistboxes:mainalbumsviewmodel/> </grid.datacontext> <listbox itemssource="{binding albums}"> <listbox.itemspanel> <itemspaneltemplate> <stackpanel orientation="horizontal"></stackpanel> </itemspaneltemplate> </listbox.itemspanel> <listbox.itemcontainerstyle> <style targettype="listboxitem"> <setter property="template"> <setter.value> <controltemplate targettype="listboxitem"> <grid margin="1"> <border x:name="mouseoverborder" horizontalalignment="stretch" verticalalignment="stretch" background="lightgreen" borderbrush="dimgray" borderthickness="1.5" visibility="collapsed"/> <border x:name="selectedborder" horizontalalignment="stretch" verticalalignment="stretch" background="green" borderbrush="black" borderthickness="1.5" visibility="collapsed"/> <contentpresenter content="{templatebinding content}" contenttemplate="{staticresource listboxitemdatatemplate}" /> </grid> <controltemplate.triggers> <!--uncomment these trigger in order make mouse on border visible--> <!--<trigger property="listboxitem.ismouseover" value="true"> <setter targetname="mouseoverborder" property="visibility" value="visible"/> </trigger> <trigger property="listboxitem.ismouseover" value="false"> <setter targetname="mouseoverborder" property="visibility" value="collapsed"/> </trigger>--> <trigger property="listboxitem.isselected" value="true"> <setter targetname="selectedborder" property="visibility" value="visible"/> </trigger> <trigger property="listboxitem.isselected" value="false"> <setter targetname="selectedborder" property="visibility" value="collapsed"/> </trigger> </controltemplate.triggers> </controltemplate> </setter.value> </setter> </style> </listbox.itemcontainerstyle> </listbox> </grid>
every time check checkbox checks checkboxes in its' row (all other albums).
managed in view-models using shared models
/// <summary> /// main view model /// </summary> public class mainalbumsviewmodel:baseobservableobject { private readonly iselectioneventaggregator _selectioneventaggregator; private readonly isongsprovider _songsprovider; private observablecollection<albumviewmodel> _albums; public mainalbumsviewmodel() { _selectioneventaggregator = new selectioneventaggregator(); _songsprovider = new songsprovider(); albums = new observablecollection<albumviewmodel> { new albumviewmodel(_selectioneventaggregator, _songsprovider), new albumviewmodel(_selectioneventaggregator, _songsprovider), new albumviewmodel(_selectioneventaggregator, _songsprovider), }; albums.tolist().foreach(model => { _songsprovider.registersongs(model, new list<selectableviewmodel> { new selectableviewmodel(_selectioneventaggregator){name = "song a", description = "description a"}, new selectableviewmodel(_selectioneventaggregator){name = "song b", description = "description b"}, new selectableviewmodel(_selectioneventaggregator){name = "song c", description = "description c"}, new selectableviewmodel(_selectioneventaggregator){name = "song d", description = "description d"}, }); }); } public observablecollection<albumviewmodel> albums { { return _albums; } set { _albums = value; onpropertychanged(); } } } /// <summary> /// album view-model /// </summary> public class albumviewmodel:baseobservableobject { public albumviewmodel(iselectioneventaggregator selectioneventaggregator, isongsprovider songsprovider) { _selectioneventagreggator = selectioneventaggregator; _songsprovider = songsprovider; //you should think unsubscribe mechanism _selectioneventagreggator.selectioneventhandler += selectioneventagreggatoronselectioneventhandler; } private void selectioneventagreggatoronselectioneventhandler(object sender, selectioneventargs args) { var key = args.key selectableviewmodel; if(key == null) return; var existingsong = songs.firstordefault(model => model.name.equals(key.name) && model.description.equals(key.description)); if(existingsong == null) return; existingsong.updateselectionsilentely(args.isselected); } private observablecollection<selectableviewmodel> _songs; private readonly iselectioneventaggregator _selectioneventagreggator; private readonly isongsprovider _songsprovider; public observablecollection<selectableviewmodel> songs { { return _songs ?? (_songs = new observablecollection<selectableviewmodel>(_songsprovider.getsongs(this))); } } } /// <summary> /// helps provide songs /// </summary> public interface isongsprovider { list<selectableviewmodel> getsongs(object albumkey); void registersongs(object albumkey, ienumerable<selectableviewmodel> songs); } class songsprovider : isongsprovider { private dictionary<object, list<selectableviewmodel>> _albums = new dictionary<object, list<selectableviewmodel>>(); public list<selectableviewmodel> getsongs(object albumkey) { return _albums.containskey(albumkey) == false ? null : _albums[albumkey]; } public void registersongs(object albumkey, ienumerable<selectableviewmodel> songs) { if (_albums.containskey(albumkey) == false) { if(songs == null) return; _albums.add(albumkey, songs.tolist()); } else { if (songs == null) { _albums.remove(albumkey); return; } _albums[albumkey] = songs.tolist(); } } } /// <summary> /// single song view-model /// </summary> public class selectableviewmodel:baseobservableobject { private readonly iselectioneventaggregator _selectioneventaggregator; private bool _isselected; private string _name; private string _description; public selectableviewmodel(iselectioneventaggregator selectioneventaggregator) { _selectioneventaggregator = selectioneventaggregator; } public bool isselected { { return _isselected; } set { _isselected = value; onpropertychanged(); _selectioneventaggregator.publish(new selectioneventargs {key = this, isselected = _isselected}); } } public string name { { return _name; } set { _name = value; onpropertychanged(); } } public string description { { return _description; } set { _description = value; onpropertychanged(); } } public void updateselectionsilentely(bool isselected) { _isselected = isselected; onpropertychanged(() => isselected); } } /// <summary> /// helps manage selection /// </summary> public interface iselectioneventaggregator { event eventhandler<selectioneventargs> selectioneventhandler; void publish(selectioneventargs selectioneventargs); } public class selectioneventaggregator : iselectioneventaggregator { public event eventhandler<selectioneventargs> selectioneventhandler; public void publish(selectioneventargs selectioneventargs) { onselectioneventhandler(selectioneventargs); } protected virtual void onselectioneventhandler(selectioneventargs e) { var handler = selectioneventhandler; if (handler != null) handler(this, e); } } public class selectioneventargs:eventargs { public object key { get; set; } public bool isselected { get; set; } }
baseobservableobject - simple inpc
/// <summary> /// implements inotifypropertychanged (.net 4.5) /// </summary> public class baseobservableobject : inotifypropertychanged { public event propertychangedeventhandler propertychanged; protected virtual void onpropertychanged([callermembername] string propertyname = null) { var handler = propertychanged; if (handler != null) handler(this, new propertychangedeventargs(propertyname)); } protected virtual void onpropertychanged<t>(expression<func<t>> raiser) { var propname = ((memberexpression)raiser.body).member.name; onpropertychanged(propname); } protected bool set<t>(ref t field, t value, [callermembername] string name = null) { if (!equalitycomparer<t>.default.equals(field, value)) { field = value; onpropertychanged(name); return true; } return false; } }
explanation:
the main idea second part of question use kind of event aggregation.
regards.
Comments
Post a Comment