Click here to Skip to main content
12,552,576 members (61,421 online)
Click here to Skip to main content
Add your own
alternative version


3 bookmarked

Single Selection Across Multiple ItemsControls

, 26 Oct 2012 Apache
Rate this:
Please Sign up or sign in to vote.
How to implement a single selection set across as many ItemsControls as your app needs.


In this article I will show you how to implement a single selection set across as many ItemsControls as your app needs.


I was building an app that has a calendar interface where each day contained a ListBox of items, and the backing collection for each day was contained in the ViewModel for that day. When I ran the app for the first time, I was appalled (though I shouldn't have been) that each ListBox manages its own selection. That meant that I was unable to deselect an item in one day by merely selecting an item in another day, although this was the behavior I wanted. 

After posting my question on another site, the only answers I received were to combine all of the items into a central collection and use the ListBox's IsSynchronizedWithCurrentItem property, but alas, this didn't work for me since my architecture wouldn't allow me to combine my collections.

I had to find another solution.  

Using the code 

The code provided is an extremely simple example that can and should be expanded upon. 

To use the code you should have a thorough understanding of most of the principle behind WPF, including:

  1. Data contexts 
  2. Binding 
  3. Data templates
  4. MVVM 

Points of Interest  

Essentially the SelectionManager, combined with ISelectable objects, provides an override of the ListBox's inherent selection functionality. What is nice about this implementation is that the items displayed in the ListBox don't have to be derived from DependencyObject, which saves a lot of unneeded overhead. 

Another key point is that this approach allows the developer to maintain MVVM practices. 

The first thing needed is a way for an object to indicate that it is selected. That is, it needs an IsSelected property. The best way to ensure that is to create an interface that the object must implement. 

public interface ISelectable
    bool IsSelected { get; set; }

That should do. Next up, we should probably create a wrapper class for any types that we don't control (and therefore cannot explicitly make them implement ISelectable).

class Selectable<T> : INotifyPropertyChanged, ISelectable
    private bool _isSelected;
    public bool IsSelected
        get { return _isSelected; }
            _isSelected = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("IsSelected"));
    public T Value { get; set; }
    public Selectable(T t)
        Value = t;
    public event PropertyChangedEventHandler PropertyChanged;

Notice here that INotifyPropertyChanged is also implemented. This is an important part since we want our interface to update visually when the selection (IsSelected property) changes.

We also need a manager that will handle which objects are selected.

public class SelectionManager
    private List<ISelectable> _selectedItems;
    public ISelectable SelectedItem
        get { return _selectedItems.LastOrDefault(); }
        set { Select(value); }
    public SelectionManager()
        _selectedItems = new List<ISelectable>();
    public void Select(ISelectable item, bool append = false)
        if (!append)
            _selectedItems.ForEach(i => i.IsSelected = false);
        if (item == null) return;
        item.IsSelected = true;

Simple yet effective. This affords us an easy way to change the selection of items by setting and clearing the IsSelected property for each item.

Almost done. We need to wire it into our UI. The first step is to implement a couple commands in our view model.

// this will be the content of our lists
public ObservableCollection<Selectable<int>> Numbers { get; set; }
public ObservableCollection<Selectable<DateTime>> Dates { get; set; }
// Need an instance of our SelectionManager
private SelectionManager _selectionManager = new SelectionManager();
public ICommand SelectItem
    get { return new SimpleDelegateCommand(i => SelectItemExecute(i)); }
public ICommand AppendSelectItem
    get { return new SimpleDelegateCommand(i => SelectItemExecute(i, true)); }
// Handles setting the selection.
private void SelectItemExecute(object obj, bool append = false)
    _selectionManager.Select((ISelectable) obj, append);

(The SimpleDelegateCommand class can be found in MSDN's documentation .)

Finally, we'll need to bind to these commands in our DataTemplates.

<DataTemplate x:Key="SelectableTemplate" DataType="{x:Type SingleSelection:ISelectable}">
    <Border x:Name="Border" Background="Transparent">
            <MouseBinding Gesture="LeftClick" CommandParameter="{Binding}"
                          Command="{Binding RelativeSource={RelativeSource FindAncestor,
            <MouseBinding Gesture="Ctrl+LeftClick" CommandParameter="{Binding}"
                          Command="{Binding RelativeSource={RelativeSource FindAncestor,
        <TextBlock x:Name="Content" Text="{Binding Value}"/>
        <DataTrigger Binding="{Binding IsSelected}" Value="True">
            <Setter TargetName="Border" Property="Background"
                    Value="{StaticResource {x:Static SystemColors.HighlightBrushKey}}"/>
            <Setter TargetName="Content" Property="Foreground"
                    Value="{StaticResource {x:Static SystemColors.HighlightTextBrushKey}}"/>

Note that we also set triggers to show that the item is selected using the current system theme. This is done because the SelectedItem property of the ListBox will not be set by clicking on the item. In fact, we don't even use the SelectedItem property anymore simply because its scope is only defined within the ListBox.

Now we just need a window with a couple ListBoxes and some items.

        <ColumnDefinition />
        <ColumnDefinition />
    <ListBox ItemsSource="{Binding Numbers}" ItemTemplate="{StaticResource SelectableTemplate}"
             HorizontalContentAlignment="Stretch" />
    <ListBox Grid.Column="1" ItemsSource="{Binding Dates}"
             ItemTemplate="{StaticResource SelectableTemplate}"
             HorizontalContentAlignment="Stretch" />
public MainWindow()
    var vm = new MainWindowViewModel
        Dates = new ObservableCollection<Selectable<DateTime>>
                                    new Selectable<DateTime>(DateTime.MinValue),
                                    new Selectable<DateTime>(DateTime.Today),
                                    new Selectable<DateTime>(DateTime.MaxValue),
        Numbers = new ObservableCollection<Selectable<int>>
                                    new Selectable<int>(1),
                                    new Selectable<int>(2),
                                    new Selectable<int>(3),
                                    new Selectable<int>(4),
                                    new Selectable<int>(5),
                                    new Selectable<int>(6),
                                    new Selectable<int>(7),
    DataContext = vm;

That's it. Running the application, we can see that when an item is clicked in either list, the selection of the other list is removed. Also, by Ctrl-clicking, we can append the selection, just like the default selection behavior of the ListBox


  • 2012/10/06 - Published article.
  • 2012/10/07 - Added code snippets.


This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0


About the Author

Greg Dennis
Software Developer
United States United States
No Biography provided

You may also be interested in...


Comments and Discussions

-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.161021.1 | Last Updated 26 Oct 2012
Article Copyright 2012 by Greg Dennis
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid