Reputation: 1661
I have an app in WPF without MVVM, I decided to refactor this to MVVM. I encountered a problem with a ComboBox SelectionChanged event. Basically to make it simpler lets assume i Have one ComboBox and 2 ListView's. Every ComboBoxItem is a collection. First ListView's ItemsSource is bound to the collection from the ComboBox.SelectedValue but only to the part whose one property(of decimal) is greater than zero. Second ListView's ItemsSource is bound to the same colection but to the second part(some prop greater than zero). Below some code to understand
private void myCombo_selectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBox myCmb = sender as ComboBox;
List<myType> myList = myCmb.SelectedValue as List<myType>;
itemsForListView1 = myList.Where((x) => x.myProp > 0);
itemsForListView2 = myList.Where((x) => x.myProp < 0);
// Above 2 collections are of Type List<myType> and their scope will be whole ViewModel,
//so i assume i just need to change them and RaisePropChanged but how to change them without breaking mvvm ?
MyListView1.ItemsSource = itemsForListView1;
MyListView2.ItemsSource = itemsForListView2;
}
How can I achieve something similiar in MVVM ?
Upvotes: 1
Views: 1670
Reputation: 333
If I understand correctly the thing you want is to handle the SelectionChanged
in ViewModel and make some changes to itemsForListView1
and itemsForListView2
instead to what you are doing in View at the moment?
1) In ViewModel you need to: create an ICommand
public property, which can be instantiated for example as DelegateCommand
from Microsoft.Practices.Composite.Presentation.Commands
:
...
public ViewModelConstructor(...)
{
...
SelectionChangedCommand = new DelegateCommand<List<myType>>(SelectionChangedExecute);
...
}
...
public List<myType> ItemsForListView1 {get; private set} // Implement INotifyPropertyChanged here
public List<myType> ItemsForListView1 {get; private set} // Implement INotifyPropertyChanged here
...
public ICommand SelectionChangedCommand { get; private set; }
private void SelectionChangedExecute(List<myType> parameter)
{
ItemsForListView1 = parameter.Where((x) => x.myProp > 0).ToList();
ItemsForListView2 = parameter.Where((x) => x.myProp < 0).ToList();
}
...
2) In View you want to bind Loaded and SelectionChanged to the newly created command in viewmodel, and you want your ListView bind to the collections in ViewModel
<ComboBox x:Name="MyComboBox" SelectedIndex="0" ItemsSource="{Binding YourCollectionWithDifferentLists}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding SelectionChangedCommand}" CommandParameter="{Binding ElementName=Combo, Path=SelectedItem}"></i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectionChangedCommand}" CommandParameter="{Binding ElementName=Combo, Path=SelectedItem}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
You might want to use ObservableCollection instead of List if your collection is changing and you want to show the changes on UI. You need to implement INotifyPropertyChanged either way if you are going to create a new collection after a selection changed event.
Upvotes: 2
Reputation: 406
I suggest a solution as in pseudo-code below. Bind SelectedItem with SelectedValue of your myCombo and ItemsListViewX with your ListView
private List<T> selectedItem;
public List<T> SelectedItem
{
get { return selectedItem; }
set
{
if (value != selectedItem)
{
selectedItem = value;
ItemsListView1 = new ObservableCollection<T>(selectedItem.Where(x=>x.Prop>0));
ItemsListView2 = new ObservableCollection<T>(selectedItem.Where(x=>x.Prop<0));
NotifyOfPropertyChange(() => SelectedItem);
}
}
}
private ObservableCollection<T> itemsListView1;
public ObservableCollection<T> ItemsListView1
{
get { return itemsListView1; }
set
{
if (value != itemsListView1)
{
itemsListView1 = value;
NotifyOfPropertyChange(() => ItemsListView1);
}
}
}
private ObservableCollection<T> itemsListView2;
public ObservableCollection<T> ItemsListView2
{
get { return itemsListView2; }
set
{
if (value != itemsListView2)
{
itemsListView2 = value;
NotifyOfPropertyChange(() => ItemsListView2);
}
}
}
Maybe you're interested also in MVVM Framework. It will enhance your databinding.
Upvotes: 2