c# - SelectedItem doesn't update properly when trying to share items between views -
i have scenario same collection of items can viewed in different ways. is, have multiple visual representations same data. in order keep our application visually clean can view 1 of these views @ time. problem i'm having if change selected item while viewing view #1 when switch view #2 selected item isn't updating properly.
my steps reproducing:
- on view #1 select item #1.
- toggle view #2 - @ point item #1 selected
- scroll down "item #200" , select it
- toggle view #1
- item #1 still highlighted , if scroll down item #200 highlighted
it seems when listbox collapsed selection changes aren't being picked up. missing? expected propertychanged events won't update ui elements if aren't visible?
i have simplified version of code below. basically, have shared array being bound 2 different listbox controls.
xaml:
<window x:class="sharedlistbindingexample.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:sharedlistbindingexample" mc:ignorable="d" title="mainwindow" height="350" width="525"> <grid> <grid.rowdefinitions> <rowdefinition height="*"/> <rowdefinition height="auto"/> </grid.rowdefinitions> <listbox grid.row="0" x:name="listbox1" itemssource="{binding list1}"> <listbox.resources> <style targettype="listboxitem"> <setter property="isselected" value="{binding path=isselected, mode=twoway}"/> </style> <datatemplate datatype="{x:type local:sharedlistitem}"> <grid horizontalalignment="stretch"> <grid.rowdefinitions> <rowdefinition height="*"/> <rowdefinition height="auto"/> </grid.rowdefinitions> <button background="red" /> <label grid.row="1" content="{binding name}" /> </grid> </datatemplate> </listbox.resources> </listbox> <listbox grid.row="0" x:name="listbox2" itemssource="{binding list2}" background="aliceblue" visibility="collapsed"> <listbox.resources> <style targettype="listboxitem"> <setter property="isselected" value="{binding path=isselected, mode=twoway}"/> </style> <datatemplate datatype="{x:type local:sharedlistitem}"> <label content="{binding name}" horizontalalignment="stretch" horizontalcontentalignment="stretch"/> </datatemplate> </listbox.resources> </listbox> <button grid.row="1" click="button_click">toggle view</button> </grid> </window>
code behind:
using system.windows; namespace sharedlistbindingexample { /// <summary> /// interaction logic mainwindow.xaml /// </summary> public partial class mainwindow : window { public mainwindow() { initializecomponent(); } private void button_click(object sender, routedeventargs e) { if (listbox1.visibility == visibility.collapsed) { listbox1.visibility = visibility.visible; listbox2.visibility = visibility.collapsed; } else { listbox2.visibility = visibility.visible; listbox1.visibility = visibility.collapsed; } } } }
viewmodel:
using system.collections.generic; namespace sharedlistbindingexample { public class twopropertiesforsamelistviewmodel { private readonly list<sharedlistitem> _sharedlist; public twopropertiesforsamelistviewmodel() { _sharedlist = new list<sharedlistitem>(); (int = 0; < 300; i++) { _sharedlist.add(new sharedlistitem($"item #{i}")); } } public ienumerable<sharedlistitem> list1 { { return _sharedlist; } } public ienumerable<sharedlistitem> list2 { { return _sharedlist; } } } }
sharedlistitem:
using system.componentmodel; namespace sharedlistbindingexample { public class sharedlistitem : inotifypropertychanged { private bool _isselected; public sharedlistitem(string name) { name = name; } public string name { get; set; } public bool isselected { { return _isselected; } set { if (value != _isselected) { _isselected = value; onpropertychanged("isselected"); } } } public event propertychangedeventhandler propertychanged; private void onpropertychanged(string propertyname = null) { propertychanged?.invoke(this, new propertychangedeventargs(propertyname)); } } }
i believe need use collectionviewsource
object between 2 different views keep selected item in sync. similar in own application.
i have 1 control defines collectionviewsource
resource in xaml:
<usercontrol.resources> <collectionviewsource x:key="dataview" /> </usercontrolresources>
the control has dependencyproperty
collectionviewsource
allows data bound other controls:
public static readonly dataviewproperty = dependencyproperty.register( "dataview", typeof( collectionviewsource ), typeof( yourcontroltype ), new propertymetadata( null ) ); public collectionviewsource dataview { { return (collectionviewsource) getproperty( dataviewproperty); } set { setproperty( dataviewproperty, value ); }
then in components constructor, after calling initializecomponent
, have execute code this:
public myusercontrol() { initializecomponent(); dataview = findresource( "dataview" ) collectionviewsource; dataview.source = yourobservablecollection; }
in other view(s) want share object, create new collectionviewsource dependencyproperty
. allows bind 2 proeprties each other in window has different views of data. in second control, have observablecollection
object property, not initialized in control's constructor. in control's loaded
event handler, set observablecollection
property's value value of collectionviewsource
object's source property. is:
if ( datacollection == null && dataview != null ) { datacollection = (observablecollection<datatype>) dataview.source; datagrid.itemssource = dataview.view; }
after this, both controls share same observablecollection
, same collectionviewsource
. it's collectionviewsource
keeps 2 control's selected item in sync.
obviously, can share collectionviewsource
object across many views like. 1 control has declare object, others have share it.
Comments
Post a Comment