Thursday, 12 February 2009

How to Databind to a SelectedItems property in WPF

Many moons ago, I asked on the WPF forums if anybody had a way of data-binding the SelectedItems property of a ListBox. Standard data binding doesn’t work, because the SelectedItems property is read-only, and understandably so: how would you like it if I injected an arbitrary collection into your ListBox and expected you to keep it up to date as the selection changed?

As no one gave me an answer, I was forced to use my gray-matter and invent a solution of my own. Since a similar question came up again recently on Stack Overflow, I thought I’d share what I came up with.

In my solution, I define an attached property that you attach to a ListBox (or DataGrid, or anything that inherits from MultiSelector) and allows you to specify a collection (via data binding, of course) that you want to be kept in sync with the SelectedItems collection of the target. To work properly, the collection you give should implement INotifyCollectionChanged – using ObservableCollection<T> should do the trick. When you set the property, I instantiate another class of my invention, a TwoListSynchronizer. This listens to CollectionChanged events in both collections, and when either changes, it updates the other.

To help me demonstrate, I’ve knocked up a toy ViewModel: it has on it an AvailableNames property that will be the data source for the ListBox, a SelectedNames property which is the reason we’re going through the whole exercise, and a Summary property which displays the number of selected items to prove that the data binding is working correctly.  I won’t bore you with the code – see the download link below.

The XAML looks like this:

<Window x:Class="SelectedItemsBindingDemo.Window1"
  Title="SelectedItems Binding Demo" Height="300" Width="300"
  <Grid Margin="5">
      <RowDefinition Height="*"/>
      <RowDefinition Height="Auto"/>
    <TextBlock Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Center"
               Text="{Binding Summary}" FontWeight="Bold" Margin ="0,5,5,5"/>
    <Button Content="Select All" Command="{Binding SelectAll}" Grid.Row="1"
            HorizontalAlignment="Right" VerticalAlignment="Center"/>
    <ListBox Grid.Row="0"
             ItemsSource="{Binding AvailableNames}"
             ff:MultiSelectorBehaviours.SynchronizedSelectedItems="{Binding SelectedNames}"
             SelectionMode="Extended" />

All the magic is initiated by line 22 where I set the attached property MultiSelectorBehaviours.SynchronizedSelectedItems using a data binding to my SelectedNames property. With that in place the SelectedNames collection in my ViewModel is updated whenever SelectedItems on the ListBox changes. And to prove it works the other way to, I’ve created a SelectAll command on the ViewModel that puts all available names into the SelectedNames collection. When you press the button you’ll see that the ListBox obediently updates to show all items selected.

The TwoListSynchronizer code does not make especially thrilling reading, so I won’t show it here. If you should peruse it however, there are a couple of things you might wonder about:

  • I’ve made it implement IWeakEventListener so that it can subscribe to CollectionChanged events using weak events. This means I don’t have to worry about creating managed memory leaks if the source SelectedItems collection has a longer lifetime than the ListBox.
  • The code occasionally refers to something called a IListItemConverter. I’m not make use of this in this application of the TwoListSynchronizer, but it might have uses elsewhere. The scenario I had in mind was where there is some kind of mapping between the items in the two collections that need to be synchronized.

Update (25/07/2013): All the code is now available on Github (under a Public Domain License). Download a zip file directly here.


Anthony Brien said...

Great article. I got it to work successfully, but only if I start with no selection. If I already have selected items at load time, the SynchronizedSelectedItems attached property seems to get bound before the ItemsSource, so it clears the selected items.

Is there a way to ensure the ItemsSource has populated the list before the Synchronization kicks in?

Anthony Brien said...

I think I got it working now and might have found a bug. If I swap _targetList and _masterList in ListSynchronizer.SetListValuesFromSourceTwo, things work for me.

Sam said...

Thanks for letting me know about this. I'll look into it when I get a chance.

Anonymous said...

Thanks for the solution. It works well. I had the same issue Anthony wrote about. I applied his change and it appears to be behaving the way I expect.

Echilon said...

me here, it works when I swap the parameters.

Great snippet though, thanks.

nitzzzu said...

This is pure gold. Thank you!

Anonymous said...

This really made my day! Thanks a lot!!!

Hendrik said...

Great stuff!

One thing: I'd like to enhance this thing to be aware of sort of "reinstanciation" of the source list:

List = new ObservableCollection<string>();

where List is a DependencyProperty of a superior object.

The listeners must somehow be made aware of this new list instance. Any idea?

Hendrik said...

Ah, as I've just seen, it is aware of a new list instance. But for some reason the new list instance gets fed with the values of the old list instead of setting the target (a ListBox in this case) to its initial values.

Hendrik said...

Arr... okay, it's the same issue Anthony Brien mentioned some months ago. I swapped sourceList and targetList in the TwoListSynchronizer.SetListValuesFromSource method and now it works as supposed. Programmatic changes to the bound collection are correctly propagated to the SelectedItems collection of the bound ListBox.

Anonymous said...

Does this work with a multi column ListView?

Sam said...

@Anonymous: I can see no reason why it wouldn't work with ListView - ListView inherits from ListBox, and the multi-column nature of ListView doens't affect the way selection works.

@Hendrik: Glad you're finding this useful. When I get a moment, I'll try to update the code with Anthony's bug fix.

Anonymous said...

When using it with a ListView, my binding to the multi column ListView is an ObservableCollection for CustomDataClass instead of the ObservableCollection for string I used with a ListBox. When I select a row, the converter throws an exception because it cannot convert CustomDataClass to string.

Sam said...

@Anonymous: so your data source (bound to the ItemsSource property on the ListView) is of type ObservableCollection<CustomDataClass>, correct? Have you made sure that the property you're binding to SynchronizedSelectedItems is of the same type? If you have and it's still not working, feel free to contact me at with more details, and I'll take a look.

Anonymous said...

Trying this great snippet with Visual Studio 4 Beta1 I'll get following exception in designer:

'Cannot create an instance of "IList".'
C:\Users\...\Window1.xaml 20 7 SelectedItemsBindingDemo

Compiled program works.

Bye Stefan

Oskar said...

Thanks Sam, this is great stuff! Really helped me a lot!

Anonymous said...

Is there a license attached to this code?

Sam said...

All the code on this site is licensed under Creative Commons Attribution 2.0 - as shown on the sidebar ;-).

Daniel Skinner said...


Excellent piece of code, this is massively useful for MVVM!

I am trying to pre-populate my SelectedItems in the constructor of the ViewModel but this is not reflected in the SelectedItems property. What do I need to change?



Sam said...

I think that might be a bug in my code. See Anthony's comment above - try swapping _targetList and _masterList in ListSynchronizer.SetListValuesFromSourceTwo

Stuart Allen said...

thanks for this code, very helpful when doing MVVM.

Anonymous said...

thx, you saved my day. i m not that good with .net yet, trying to get into mvvm and you solved the hell of a problem for me.

Todd said...

I am sorry to bother you with this but I am unable to find the "SetListValuesFromSourceTwo" method everyone is talking about in the source code to fix the issue with MVVM and setting up the selected items before binding. What am I missing? I used this link and that method name certainly does not exist in any of that code.

Sam said...

I think the "Two" belongs with the class name rather than the method name - it should be TwoListSynchronizer.SetListValuesFromSource.

But I think I've found a better place for the bug fix anyway: in line 103 of the MultiSelectorBehaviors file, swap the parameters to the TwoListSynchronizer constructor.

Anonymous said...


Thanks for this code too. Sorry for the long comment - I have a query and a cautionary tale.

i've found that if you change the datacontext of a parent control then the listbox control will clear all it's selected items. Since the weak events are still attached at this point your target list will be cleared too. Wasnt what i wanted so i remove these event listeners in a data context changed event handler for the control (added to MultiSelectorBehaviour). Not a bug in your code (unexpected behaviour in the framework) but the consequences of this when databound can be higher.

The query is related to the StartSynchronizing method - you check TargetAndMasterCollectionsAreEqual() and potentially synchronise in the opposite direction. The comment above this call mentions "(This is the case with a ListBox SelectedItems collection: only items from the ItemsSource can be included in SelectedItems)" - but i don't follow. Can this case only ever arise if the ConvertFromMasterToTarget fails for an item ?

Sam said...

Yes, I've seen that behaviour, but I don't have a proven general-purpose solution unfortunately.

The comment you refer to: what this means is that if you try to add an item to the ListBox SeleectedItems collection that isn't in the ListBox ItemsSource collection, the item won't get added. You might get into this situation if you cached the previous list of SelectedItems, but meanwhile the ItemsSource collection has changed. So I synchronise back in the other direction to make sure there are no erroneous items in SelectedItems. If you always pre-filter your SelectedItems collection then you can safely remove that call.

Jmix90 said...

Nice article !

Anonymous said...

je ne sais pas beaucoup l'anglais , alors,
je peut ecrire en français mon problème?

Sam said...

Je connais probablement encore moins français. Essayez

Anonymous said...

Thanks for this brilliant and usefull behaviour !

Anonymous said...

Hi Sam,
before i read your execllent article, i find my stupid solution. just like this

in file.xaml

in file.cs

public partial class MyControl: UserControl
public MyControl()
DataContextChanged += OnDataContextChanged;

private void checkedListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
((ISelectionChanged) DataContext).SelectedItems = OpCheckedListView.SelectedItems;

in viewModel.cs

public IList SelectedItems
get { return _selectedItems; }
if (_selectedItems != value)
_selectedItems = value;
((ISelectionChanged) DataContext).SelectedItems = OpCheckedListView.SelectedItems;

this run, but this is not generic, i think.
can you give me some suggestion? or improve this piece of code?


Anonymous said...

i just forget this code in file.xaml


Anonymous said...

i just forget this code in file.xaml

ListView x:Name="OpCheckedListView"
SelectionMode="Multiple" SelectionChanged="checkedListView_SelectionChanged"
ItemsSource="{Binding AList}"

Anonymous said...

Thanks for taking the effort to work it out.
Nice solution!

Anonymous said...

Thanks sam for this nice solution it works perfect!


Anonymous said...

Will this work in Silverlight?

Sam said...

It can be made to work in Silverlight, but it's not a copy-and-paste job unfortunately.

If I get time, I'll post my Silverlight version later.

pyrahna said...

I'm new to the whole MVVM concept but I am having a hard time finding where your code actually changes the values in _selectedNames. I would have assumed there was a set command for SelectAll but there is not. How do you actually set new values of _selectedNames.
thanks for the code and the help

Sam said...

I presume you've downloaded the code? If you look in ViewModel.cs at the SelectAll property, you see that I change the selected names by adding and removing items from the SelectedNames collection. The magic is that this is then reflected automatically in the items that are selected in the ListBox.

Does that help?

pyrahna said...

I have downloaded the code. I am still trying to figure out how the list is updated if I manually select a single item in the list. When I put a break point in the SelectAll command it does not stop there.

Sam said...

@pyrahna, To see what's happening, you'd need to point a breakpoint in TwoListSynchronizer.HandleCollectionChanged - that's where changes made to the one list are propagated to the other.

pyrahna said...

It appears that my ReceiveWeakEvent isn't being thrown. Any idea why that might be?

Rémy said...

Very useful!
I thought it wasn't enough at first sight because of the reported and fixed bug, then I deleted it, and downloaded it again after having read the comments =)
You really have to update the archive :D

N3tM4n said...

Please take a look, maybe you known the solution...

Sam said...

Thanks for pointing out the question. I'm afraid I don't have a good solution to it at the moment, but I'll give it some thought.

Lisa said...

Hello Sam,

in the whole project there exists nothing like:

I have the same bug the others experience. Would you please show me where exactly to change this?

Miami MLs said...

You can see the location and other amenities of the condo. This will give idea how is it like living in a Miami condo.
Miami MLS

LVSC said...

Has any one done this twoway binding in Silverlight ? it really givesme such a pain!

Anonymous said...

To save anyone else time, you can absolutely bind to ListBox's selected item:

You cannot to a ListView without a workaround:

pyrahna said...

I have downloaded the code and discovered a weird behavior. If you add a second list box under the first, , and select some items on the first listbox and then select something on the second list box everything appears to disappear in the 1st listbox. Those items are still selected in the VM but the are not visible in the view. Does anyone know how to address this?

Kamran A said...

You should upload this to GitHub for easy patching/forking :)

Sam said...

I've certainly got that on my todo list (I was also thinking of making a NuGet of it).

Anonymous said...

Hello Sam,

please make a NuGet of it and update the code, because the download link does NOT work. I selected 5 items and 2 items get deleted - it seems randomly...-

thanks in advance, bastien

Anonymous said...

Does any body used this in Silverlight.. I need Siolverlight version of this code.

Anonymous said...

Where's code ? The zip i obtain is 0 octet...

Admiral Ronton said...

Hi Sam, applied your fix to the MultiSelectorBehaviours.cs file and it worked like a charm. Very elegant solution, cheers!

neomi o said...

Hi sam, I try to upload your application , but this not download, this application is seem very useful, How do I download this application, please?Very Thanks

Benrhere said...

Has anyone gotten this to work with a binding validation? Everything binds perfectly, but the object I'm binding to I use for doing data validation. In my binding, I've got:
morestuf:MultiSelectorBehaviours.SynchronizedSelectedItems="{Binding The_selectedVersions, ValidatesOnDataErrors=True,UpdateSourceTrigger=PropertyChanged}":MultiSelectorBehaviours.SynchronizedSelectedItems="{Binding The_selectedVersions, ValidatesOnDataErrors=True,UpdateSourceTrigger=PropertyChanged}"
But it doesn't seem to work. The way that I currently got the validation to work is to attach an event handler to the ListBox's SelectionChanged event, and the following code inside:

Dim theExpression = VersionsLB.GetBindingExpression(MultiSelect.MultiSelectorBehaviours.SynchronizedSelectedItems)


With this in place, everything works perfectly, but it would be nice not to have to wire up an event handler. Does code need to be included in the MultiSelect that checks to see if ValidatesOnDataErrors is set, and act on it? This seems to happen automatically when you bind in a regular scenario.

Any thoughts would be greatly appreciated!


Samuel Jack said...

   Setting ValidatesOnDataErrors=True in the binding causes validation to happen when the value of the property changes. But in typical usage the value of the SynchronizedSelectedItems property only changes when the control is first loaded and a collection is assigned to it. When the selection in the ListBox changes, it is the collection contents which change, and the data binding system is unaware of that.

I can't think of anything you could do my behavior code which would help here, because validation happens at the level of the properties on the ViewModel.

An alternative to your fix that you might try (assuming you're using the Model-View-ViewModel pattern): in your ViewModel, add an event handler to the CollectionChanged event of your SelectedItems collection  (the one you're binding to the ListBox, exposed in the property The_selectedVersions). In that event handler, raise a PropertyChanged event for the The_selectedVersions property.

Benrhere said...

Hey Sam,
First, thanks for replying!
I think your solution would work well. (I am indeed trying to implement the MVVM patern.)

I successfully added an event handler to the_selectedVersions.CollectionChanged, and in that event handler, I tried to raise the PropertyChanged event.

But I've got a question: As events must be raised from inside the owning class, how could I raise a PropertyChanged event on the The_selectedVersions ObservableCollection? I also tried calling the method OnPropertyChanged, but not surprisingly, I got:Error 1 'System.Collections.ObjectModel.ObservableCollection(Of T).Protected Overridable Sub OnPropertyChanged(e As System.ComponentModel.PropertyChangedEventArgs)' is not accessible in this context because it is 'Protected'.I'm wondering if there's something that I misunderstood?Thanks Sam...-Ben
The_selectedVersions ObservableCollection? I also tried calling the method OnPropertyChanged, but not surprisingly, I got:

Error 1 'System.Collections.ObjectModel.ObservableCollection(Of T).Protected Overridable Sub OnPropertyChanged(e As System.ComponentModel.PropertyChangedEventArgs)' is not accessible in this context because it is 'Protected'.

I'm wondering if there's something that I misunderstood?

Thanks Sam...


Samuel Jack said...

Ben, you don't need to raise the PropertyChanged event from the ObservableCollection, but from the ViewModel, with the property name being the property that holds the observable collection.

Here's a small example:

public class MyViewModel : ViewModelBase
   public ObservableCollection SelectedItems {get; private set;}
   public MyViewModel() 
      SelectedItems = new ObservableCollection();
      SelectedItems.CollectionChanged += delegate { RaisePropertyChanged("SelectedItems"); };


Benrhere said...

Sam, that's fantastic. With your example, I was able to get it to work! Now my view is nice and clean :)

Samuel Jack said...

Excellent - glad I could help.

physician assistant said...

I discovered your web site via Google while looking for a related subject, lucky for me your web site came up, it seems to be great. I have bookmarked it in my google bookmarks.

physician assistant said...

I discovered your web site via Google while looking for a related subject, lucky for me your web site came up, it seems to be great. I have bookmarked it in my google bookmarks.

TeBeCo said...

(I hope my english will be eas for reader to understand, i appologize for incoming eyes issues you may encounter)

Scenario : 
We're using this behavior in an application using MVVM, onto a ListBox. Nothing special.
We're loading the ViewModel First, then the View
we have something like : 


    Public Property SelectedItems() As ObservableCollection(Of Item)

Public MustInherit Class ViewModelBase
    Public MustOverride Sub LoadData(ByVal param As Object)
End Class

In the Abstract Method, we should load Data for the current view, and for that view, i should have a default multiple selection, here for example i have :
SelectedItems = new ObservableCollection(Of Item)(AvailableItems)

that way, it should select all values but the first one.

Problem : There's no selection at all

Tips / Fix ? :

To do that i had to change a little bit that method :

    Public Sub StartSynchronizing()        ListenForChangeEvents(_masterList)        ListenForChangeEvents(_targetList)        ' Update the Target list from the Master list        SetListValuesFromSource(_masterList, _targetList, AddressOf ConvertFromMasterToTarget)        ' In some cases the target list might have its own view on which items should included:        ' so update the master list from the target list        ' (This is the case with a ListBox SelectedItems collection: only items from the ItemsSource can be included in SelectedItems)        If Not TargetAndMasterCollectionsAreEqual() Then            SetListValuesFromSource(_targetList, _masterList, AddressOf ConvertFromTargetToMaster)        End If    End Sub

to :

    Public Sub StartSynchronizing()        ListenForChangeEvents(_masterList)        ListenForChangeEvents(_targetList)        If Not TargetAndMasterCollectionsAreEqual() Then                ' In some cases the target list might have its own view on which items should included:
                ' so update the master list from the target list
                ' (This is the case with a ListBox SelectedItems collection: only items from the ItemsSource can be included in SelectedItems)
                SetListValuesFromSource(_targetList, _masterList, AddressOf ConvertFromTargetToMaster)        else                ' Update the Target list from the Master list                SetListValuesFromSource(_masterList, _targetList, AddressOf ConvertFromMasterToTarget)        End If    End Sub

because the xaml is loaded After the datacontext, it tries to copy the selection of the listbox (an empty selection), to the "tracking" collection ( SelectedItems here)

Did i miss something ? did i used it the bad way ? Is there a better way ?

TeBeCo said...

-_-' it seems that some of my breakline char didn't printou very well :(
I can't edit it, if someone here have admin rights to edit it and want to do it ... go ahead

Samuel Jack said...

   I think your fix is the best way to go.


jro said...

Has anyone tried using this with a collection that is filtered using an ICollectionView?  I.e. So I bind the collection view instead.  Whenever I update the collection view's filter and refresh, I expect there to be some sort of effect on SelectedItems for rows that are now filtered.  I assume, either (1) these filtered items are still part of my SelectedItems collections even though they are not visible on my UI; or (2) these filtered orders are magically removed from the SelectedItems collection.

Unfortunately, this is not the case, and I am seeing both occurrences happening, i.e. sometimes the filter update results in the collections removing the filtered rows; sometimes it doesn't.  

Anyone come across this?  I'm still trying to investigate further.

Qwertie said...

Thanks for providing a way for binding to SelectedItems, but I have reservations about your documentation strategy.

For example, there is a method is called "Get Synchronized Selected Items()" whose 3-line documentation comment is: "Gets the synchronized selected items". It has a parameter called "dependencyObject" whose documentation is "The dependency object." See the pattern? The return value is documented as "The list that is acting as the sync list." This comment seems to provide more information than the others, but without a clear definition of "sync list", it actually doesn't.

Ideally the documentation would tell us something that isn't immediately obvious, such as: why there are several classes (MultiSelectBehaviors, SynchronizationManager, TwoListSynchronizer) instead of just one? How do the classes fit together and how do they operate (e.g. what happens when the user clicks something? What happens when the collection changes on the viewmodel side?) What does the terminology mean (sync list, master list, target list...)? 

Guest said...

When I was a child, this was a matter of var selected = mylistbox.SelectedItems. Job done. pff kids these days..

Joba said...

Sorry, but this is not helpfull since it doesn't work properly when the seletedItems already have items in it. The suggested fix (swap the parameters) appears to work, but it does not! The items are indeed seleted in the ListBox, but when you press SelectedAll it shows 9 items selected, but only 8 are avaiable; and then if you continue to select/deselect more items nothing works anymore. Anyone fixed that?

shaks said...

Hi Sam,

I am not sure why, but I can't get this to work. I have bound the SelectedItems like this in the User Control:

In my VM I have:

public ObservableCollection AvailableItems        {            get            {                return _availableItems;            }            set            {                
_availableItems = value;                OnPropertyChanged("
AvailableItems");            }        }        public ObservableCollection SelectedItems        {            get            {                return _selectedItems;            }            set            {                
_selectedItems = value;                OnPropertyChanged("
SelectedItems");            }        }

My ViewModelBase implements the INotifyPropertyChanged from which I inherit my VM. The dependencyProperties SynchronizedSelectedItems and SynchronizationManagerProperty get initialized but the method OnSynchronizedSelectedItemsChanged is never called. 

I bind my VM to VIew like this:

                    Report objReport = new Report();                    ReportViewModel objReportgVM = new ReportViewModel();                                        objReportgVM.ViewMenuItems = LoadHeaderView(ViewName);                    objReportgVM.WindowTitle = ViewName;                    objReportgVM.Load();                                        LoadChild(objReport, objReportgVM);

And LoadChild method:
       private static void LoadChild(Object viewobj, Object viewmodelobj)        {            MWindow.pnlWorkArea.Children.Clear();            if (viewobj != null)            {                ((UserControl)viewobj).DataContext = viewmodelobj;                MWindow.pnlWorkArea.Children.Add((UIElement)viewobj);            }        }

I am not sure what am I doing wrong. Please help, I am stuck so bad.

Samuel Jack said...

What exactly is it that doesn't work here? Is it that your view model needs to know when the SelectedItems collection has changed? In that case, you need to handle the ObservableCollection.CollectionChanged event.

shaks said...

Well, the ReceiveWeakEvent method was not being called. My guess was that the dependency property was not getting attached to the ListBox Selected Items. But some miracle happened and I have a working solution. Wow, I was wondering if I would be able to even make it work, but thanks to you, works like a charm. Thanks a tonne for this wonderful solution.

VJ said...

Hey Sam, Very good article. Helped me with a custom control I am developing, similar to "Column Options" dialog in the TFS workitem query results window. Thanks.

Srabonti said...

It would be nice if you could "bore" us a little with a code walk through for beginners like I, who have trouble understanding the TowListSynchronizer and MultiSelectedBehaviors class

Aleksei said...

Thank you for your solution! It became very useful for me!

Max said...

The best solution of 'SelectedItems', I think. Works great!

Derek said...

This is awesome. Worked like a charm and will really help me stick to a more strict MVVM implementation.

Dave M said...

The link to the source code doesn't seem to work for me. Could you check it or arrange another way for me to get the source. Thanks

ReggieMcLove said...


Joe said...

@samuel_d_jack ,
Great post. I just downloaded your code and tried it in VS 2013. Everything works except the "Select All" button. When you click "Select All", it deselects everything in the ListBox, then shows in the Count that all 8 items are selected. When I debugged it, I was able to verify that the ListBox's SelectedItems property did indeed have 8 items in it, but it didn't visually show them as selected. I was very confused.
Then I upgraded the sample from WPF 3.5 to WPF 4.5.1. I ran it again and noticed that after clicking "Select All", there are now lines between each item. I realized that clicking the button set focus off of the ListBox, and thus I didn't know it was selected because when not focused, the default selected style looks an awful lot like the selected style.
So, it works perfectly. Thanks again for such a great post!

Abhi said...

I am trying to convert it to Silverlight but can find a substitute for CollectionChangedEventManager. Anyone have ideas?

Abhi said...

Sam, did you get a chance to convert it to Silverlight. I tried, but there are lot of libraries missing in Silverlight.

Post a Comment