WELCOME

This blog is where I post about my consulting work with Microsoft Technologies, and other random tidbits that don't fit in my Photo Blog or my Iraq Blog.

Wednesday, June 10, 2009

A simple method of binding the selected values of a list in WPF with MVVM

Using the MVVM pattern in WPF applications simplifies some aspects of developing and testing WPF applications, but it add quite a bit of complexity to others…

One interesting challenge I faced recently with MVVM was how to achieve two way binding of the selected values of a ListBox to a collection in a view model.  I would like to share an approach to solving this challenge using Styles and Databinding.

It’s easy to bind the values of a collection in a view model to a list, but the challenge is that you want the view model to be aware of user selections in the list without having to use traditional events an code behind.

You also want to be able to change the selected items in the view model and have those changes reflected in the UI. In my sample code (below) this is demonstrated by the “Select All” checkbox, which modifies the select items in the view model.

The key to this approach is that entities in the collection you are binding to have to have a boolean “IsSelected” property (you can name it whatever you like).  And then you create a Style to bind the IsSelected property of the ListBoxItem to the IsSelected property of the bound entity.  See the XAML sample code below:

<ListBox ItemsSource="{Binding PersonCollection}" 
SelectionMode="Multiple" >

<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>

<DataTemplate DataType="{x:Type MultiSelectMvvm:Person}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Name}"/>
<Label Content="{Binding IsSelected}"/>
</StackPanel>
</DataTemplate>
</ListBox.Resources>

</ListBox>

<CheckBox IsChecked="{Binding SelectAll}" Margin="3">
Select All
</CheckBox>


Here is the ViewModel code:



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;

namespace MultiSelectMvvm
{
public class Window1ViewModel
{
ObservableCollection<Person> personCollection;
public ObservableCollection<Person> PersonCollection
{
get
{
if (personCollection == null)
{
personCollection = new ObservableCollection<Person>();
}
return personCollection;
}
set { personCollection = value; }
}

private bool selectAll;
public bool SelectAll
{
get
{
return selectAll;
}
set
{
selectAll = !selectAll;
foreach (var person in personCollection)
{
person.IsSelected = selectAll;
}
}
}
}


public class Person : INotifyPropertyChanged
{
public string Name
{
get;
set;
}

private bool? isSelected;
public bool? IsSelected
{
get
{
return isSelected;
}
set
{
isSelected = value;
NotifyPropertyChanged("IsSelected");
}
}

public event PropertyChangedEventHandler PropertyChanged;

private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
}


FYI: Marlon over at C# Disciples wrote a recent blog post about this: Sync Multi Select Listbox with ViewModel.  His approach uses Attached Properties.

No comments: