Pass ListView SelectedItems to ViewModel in Universal apps

Pass ListView SelectedItems to ViewModel in Universal apps

One of the things that WinRT devs need to work around in Universal apps is the fact that you can't bind straight to SelectedItems of a ListView/GridView. There are a few ways to pass SelectedItems to the ViewModel and here's one that can get the job done quickly.

The method I'll use in this post uses EventTriggerBehavior to invoke a command in ViewModel when a SelectionChanged event occurs. For that to work, you need to add the Behaviors SDK to both of your projects (Windows and Windows Phone) in your Universal app.

Behaviors SDK in Universal apps

Whenever you want to use the classes from that SDK, you need to reference it in XAML

xmlns:interactivity="using:Microsoft.Xaml.Interactivity"  
xmlns:core="using:Microsoft.Xaml.Interactions.Core"  

And then you can attach the EventTriggerBehavior to ListView or GridView.

<ListView Name="MyListOfImportantThings" SelectionMode="Multiple">  
    <interactivity:Interaction.Behaviors>
        <core:EventTriggerBehavior EventName="SelectionChanged">
            <core:InvokeCommandAction Command="{Binding SelectionChangedCommand}"
                                      InputConverter="{StaticResource SelectionChangedConverter}"
                                      InputConverterParameter="{Binding ElementName=MyListOfImportantThings}" />
        </core:EventTriggerBehavior>
    </interactivity:Interaction.Behaviors>
</ListView>  

Notice that the ListView has SelectionMode set to Multiple, so that you can actually select multiple items. Also, the event that will trigger the behavior is SelectionChanged, which fires (surprise, surprise) every time selection changes.

But that's not enough. If you try to just bind to SelectedItems of your ListView to send it as CommandParameter of the Command invoked when SelectionChanged event fires, you'll notice it doesn't work. SelectedItems is a funny little property full of surprises.

That's why we use a very simple converter called SelectionChangedConverter and we pass the ListView reference to it.

public class SelectionChangedConverter : IValueConverter  
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var listView = parameter as ListView;

        return listView.SelectedItems;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

The converter takes that reference and returns the SelectedItems property.
Of course the converter needs to be defined in your App resources as StaticResource.

<Application.Resources>  
    <local:SelectionChangedConverter x:Key="SelectionChangedConverter" />
</Application.Resources>  

If you have a ViewModel behind your page with a publicly exposed command called SelectionChangedCommand, it will get invoked when SelectionChanged event occurs and you'll get the list of SelectedItems!

public RelayCommand<IList<object>> SelectionChangedCommand  
{
    get
    {
        if (selectionChangedCommand == null)
        {
            selectionChangedCommand = new RelayCommand<IList<object>>(
                items =>
                {
                    // do something with selected items!
                }
            );
        }

        return selectionChangedCommand;
    }
}

Do you use a different way of passing SelectedItems? Let me know in the comments!

Igor Ralic

igor ralic

View Comments
Microsoft Certified Solutions Developer: Windows Store Apps in C#