Monday, 19 July 2010

MVVM and Multiple Selection – Part II

In the last instalment in this series I explored a common way to communicate multiple selections between a View and a ViewModel and left the article facing a problem:

How do we handle multiple selections in the face of UI virtualization?

A solution can be found in this Stack Overflow question. The solution advises that instead of using an ItemContainerStyle to communicate the selection information between View and ViewModel, the selection should be passed using the CommandParameter property:

<ListBox x:Name="listBox" ItemsSource="{Binding Items}"/>

<Button Content="Remove Selected"
    Command="{Binding RemoveSelectedItemsCommand}"
    CommandParameter="{Binding ElementName=listBox, Path=SelectedItems}"/>

This technique bypasses UI virtualization and passes the selected items directly from the control’s SelectedItems collection to the command itself using the CommandParameter property. Problem solved.

Except we’ve now introduced a tight coupling between the ListBox containing the items and the Button that invokes the command. What if they’re located in different UserControls? For example, you might want add a MenuItem to an application’s main Window that looks something like this:

<MenuItem Header=”Print Selected” Command=”{Binding CurrentDocument.PrintSelectedItemsCommand}”/>

(this is a pattern I described recently in Using Binding.FallbackValue to Disable a UI Element When its Command can’t be Found)

Here, the MenuItem will not have access to the ListBox displaying the selected items to the user, as the ListBox is located in a child UserControl.

In this case, in order to locate the ListBox control the main Window would need to either have in-depth knowledge of its child UserControls, or some sort of mechanism to expose child ItemsControls would need to be invented. Messy.

What we really need is a MultiSelectCollectionView – I’ll describe such a thing in the next article in the series.

1 comment:

  1. Well, the other huge problem with this approach is that it's useless if you need to know about selection changes right away (not when somebody clicks a button). In my app, there is a graphical representation of a bunch of objects, with a list of the objects on the left. If somebody selects two objects in the graphical view, the selection should be mirrored in the list, and vice versa.