WPF Toolkit DataGrid Multi-Select: How to get SelectedItems out?

Shafique picture Shafique · Oct 16, 2009 · Viewed 23.4k times · Source

I'm using the WPF Toolkit's DataGrid. I've enabled the property on the DataGrid to allow for multi-selecting of rows. How do I get the SelectedItems out? I'm using an MVVM framework to bind my ViewModel to my View.

Thanks!

Answer

samneric picture samneric · Jun 7, 2011

Taking Bill's answer, merging options 1 and 2, adding a sprinkling of attached properties as an alternative to writing code-behind, I came up with a Behavior.

Firstly, we have the behavior:

Public Class SelectedItemsBehavior

    Public Shared ReadOnly SelectedItemsChangedHandlerProperty As DependencyProperty =
        DependencyProperty.RegisterAttached("SelectedItemsChangedHandler",
            GetType(mvvm.RelayCommand), GetType(SelectedItemsBehavior),
            New FrameworkPropertyMetadata(New PropertyChangedCallback(AddressOf OnSelectedItemsChangedHandlerChanged)))




    Public Shared Function GetSelectedItemsChangedHandler(ByVal element As DependencyObject) As mvvm.RelayCommand
        If element Is Nothing Then Throw New ArgumentNullException("element")
        Return element.GetValue(SelectedItemsChangedHandlerProperty)
    End Function

    Public Shared Sub SetSelectedItemsChangedHandler(ByVal element As DependencyObject, ByVal value As mvvm.RelayCommand)
        If element Is Nothing Then Throw New ArgumentNullException("element")
        element.SetValue(SelectedItemsChangedHandlerProperty, value)
    End Sub

    Private Shared Sub OnSelectedItemsChangedHandlerChanged(d As DependencyObject,
                                                            e As DependencyPropertyChangedEventArgs)

        Dim dataGrid As DataGrid = DirectCast(d, DataGrid)

        If e.OldValue Is Nothing AndAlso e.NewValue IsNot Nothing Then
            AddHandler dataGrid.SelectionChanged, AddressOf ItemsControl_SelectionChanged
        End If

        If e.OldValue IsNot Nothing AndAlso e.NewValue Is Nothing Then
            RemoveHandler dataGrid.SelectionChanged, AddressOf ItemsControl_SelectionChanged
        End If

    End Sub


    Public Shared Sub ItemsControl_SelectionChanged(sender As Object,
                                                    e As SelectionChangedEventArgs)

        Dim dataGrid As DataGrid = DirectCast(sender, DataGrid)

        Dim itemsChangedHandler As RelayCommand = GetSelectedItemsChangedHandler(dataGrid)

        itemsChangedHandler.Execute(dataGrid.SelectedItems)

    End Sub

End Class

C#:

using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
public class SelectedItemsBehavior
{


    public static readonly DependencyProperty SelectedItemsChangedHandlerProperty = DependencyProperty.RegisterAttached("SelectedItemsChangedHandler", typeof(mvvm.RelayCommand), typeof(SelectedItemsBehavior), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnSelectedItemsChangedHandlerChanged)));



    public static mvvm.RelayCommand GetSelectedItemsChangedHandler(DependencyObject element)
    {
        if (element == null)
            throw new ArgumentNullException("element");
        return element.GetValue(SelectedItemsChangedHandlerProperty);
    }

    public static void SetSelectedItemsChangedHandler(DependencyObject element, mvvm.RelayCommand value)
    {
        if (element == null)
            throw new ArgumentNullException("element");
        element.SetValue(SelectedItemsChangedHandlerProperty, value);
    }


    private static void OnSelectedItemsChangedHandlerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        DataGrid dataGrid = (DataGrid)d;

        if (e.OldValue == null && e.NewValue != null) {
            dataGrid.SelectionChanged += ItemsControl_SelectionChanged;
        }

        if (e.OldValue != null && e.NewValue == null) {
            dataGrid.SelectionChanged -= ItemsControl_SelectionChanged;
        }

    }



    public static void ItemsControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        DataGrid dataGrid = (DataGrid)sender;

        RelayCommand itemsChangedHandler = GetSelectedItemsChangedHandler(dataGrid);

        itemsChangedHandler.Execute(dataGrid.SelectedItems);

    }

}

Then we add it to the datagrid in XAML:

<DataGrid AutoGenerateColumns="False" FontFamily="Tahoma" FontSize="9"
          ItemsSource="{Binding Path=ResultsVM}" 
          mvvm:SelectedItemsBehavior.SelectedItemsChangedHandler="{Binding Path=ResultsSelectionChangedCommand}" />

Then we code the RelayCommand in the ViewModel:

    Public ReadOnly Property ResultsSelectionChangedCommand() As mvvm.RelayCommand
        Get
            If _resultsSelectionChangedCommand Is Nothing Then
                _resultsSelectionChangedCommand = New mvvm.RelayCommand(AddressOf ResultsSelectionChanged)
            End If
            Return _resultsSelectionChangedCommand
        End Get
    End Property

    Public Sub ResultsSelectionChanged(ByVal selectedItems As Object)

        _resultsSelectedItems.Clear()
        For Each item In selectedItems
            _resultsSelectedItems.Add(item)
        Next

    End Sub

C#:

public mvvm.RelayCommand ResultsSelectionChangedCommand {
    get {
        if (_resultsSelectionChangedCommand == null) {
            _resultsSelectionChangedCommand = new mvvm.RelayCommand(ResultsSelectionChanged);
        }
        return _resultsSelectionChangedCommand;
    }
}


public void ResultsSelectionChanged(object selectedItems)
{
    _resultsSelectedItems.Clear();
    foreach (item in selectedItems) {
        _resultsSelectedItems.Add(item);
    }

}

The _resultsSelectedItems is simply a list of items displayed in the DataGrid:

    Private _resultsSelectedItems As New List(Of WorkOrderMatchViewModel)

C#:

private List<WorkOrderMatchViewModel> _resultsSelectedItems = new List<WorkOrderMatchViewModel>();

Hope this helps, kinda uses both of Bill's methods without having to reference MVVM-Light.