c# - Binding SelectedItems of ListView to ViewModel -
i have list view binding items property in viewmodel.
<listview height="238" horizontalalignment="left" name="listview" verticalalignment="top" width="503" itemssource="{binding businesscollection}" selectionmode="multiple" > <listview.view> <gridview> <gridview.columns> <gridviewcolumn> <gridviewcolumn.celltemplate> <datatemplate> <checkbox ischecked="{binding relativesource={relativesource ancestortype={x:type listviewitem}}, path=isselected}" /> </datatemplate> </gridviewcolumn.celltemplate> </gridviewcolumn> <gridviewcolumn displaymemberbinding="{binding id}" header="id" /> <gridviewcolumn displaymemberbinding="{binding name}" header="name" /> </gridview.columns> </gridview> </listview.view> </listview>
and in viewmodel.
icollectionview _businesscollection public icollectionview businesscollection { {return _businesscollection;} set{ _businesscollection=value; raisepropertyonchange("businesscollection"); } }
how selected item of businesscollection in viewmodel?
1. 1 way source binding:
you have use selectionchanged
event. easiest way write eventhandler in codebehind "bind selecteditems" viewmodel.
//viewmodel public icollectionview businesscollection {get; set;} public list<yourbusinessitem> selectedobject {get; set;} //codebehind private void listview_selectionchanged(object sender, selectionchangedeventargs e) { var viewmodel = (viewmodel) datacontext; viewmodel.selecteditems = listview.selecteditems .cast<yourbusinessitem>() .tolist(); }
this still aligns mvvm design, because view , viewmodel resposibilities kept separated. dont have logic in codebehind , viewmodel clean , testable.
2. 2 way binding:
if need update view, when viewmodel changes, have attach viewmodel's propertychanged
event , selected items' collectionchanged
event. of course can in codebehind, in case create more reusable:
//viewmodel public observablecollection<yourbusinessitem> selectedobject {get; set;} //in codebehind: var binder = new selecteditemsbinder(listview, viewmodel.selecteditems); binder.bind();
or can create custom attached property, can use binding syntax in xaml:
<listview local:listviewextensions.selectedvalues="{binding selecteditem}" .../>
public class selecteditemsbinder { private listview _listbox; private ilist _collection; public selecteditemsbinder(listview listbox, ilist collection) { _listbox = listbox; _collection = collection; _listbox.selecteditems.clear(); foreach (var item in _collection) { _listbox.selecteditems.add(item); } } public void bind() { _listbox.selectionchanged += listbox_selectionchanged; if (_collection inotifycollectionchanged) { var observable = (inotifycollectionchanged) _collection; observable.collectionchanged += collection_collectionchanged; } } public void unbind() { if (_listbox != null) _listbox.selectionchanged -= listbox_selectionchanged; if (_collection != null && _collection inotifycollectionchanged) { var observable = (inotifycollectionchanged) _collection; observable.collectionchanged -= collection_collectionchanged; } } private void collection_collectionchanged(object sender, notifycollectionchangedeventargs e) { foreach (var item in e.newitems ?? new object[0]) { if (!_listbox.selecteditems.contains(item)) _listbox.selecteditems.add(item); } foreach (var item in e.olditems ?? new object[0]) { _listbox.selecteditems.remove(item); } } private void listbox_selectionchanged(object sender, selectionchangedeventargs e) { foreach (var item in e.addeditems ?? new object[0]) { if (!_collection.contains(item)) _collection.add(item); } foreach (var item in e.removeditems ?? new object[0]) { _collection.remove(item); } } }
attached property implementation
public class listboxextensions { private static selecteditemsbinder getselectedvaluebinder(dependencyobject obj) { return (selecteditemsbinder)obj.getvalue(selectedvaluebinderproperty); } private static void setselectedvaluebinder(dependencyobject obj, selecteditemsbinder items) { obj.setvalue(selectedvaluebinderproperty, items); } private static readonly dependencyproperty selectedvaluebinderproperty = dependencyproperty.registerattached("selectedvaluebinder", typeof(selecteditemsbinder), typeof(listboxextensions)); public static readonly dependencyproperty selectedvaluesproperty = dependencyproperty.registerattached("selectedvalues", typeof(ilist), typeof(listboxextensions), new frameworkpropertymetadata(null, onselectedvalueschanged)); private static void onselectedvalueschanged(dependencyobject o, dependencypropertychangedeventargs value) { var oldbinder = getselectedvaluebinder(o); if (oldbinder != null) oldbinder.unbind(); setselectedvaluebinder(o, new selecteditemsbinder((listbox)o, (ilist)value.newvalue)); getselectedvaluebinder(o).bind(); } public static void setselectedvalues(selector elementname, ienumerable value) { elementname.setvalue(selectedvaluesproperty, value); } public static ienumerable getselectedvalues(selector elementname) { return (ienumerable)elementname.getvalue(selectedvaluesproperty); } }
Comments
Post a Comment