WPF工具包数据网格多选:如何获取所选项目?

9
我正在使用WPF Toolkit的DataGrid。我已经启用了DataGrid上的属性以允许多选行。我该如何获取所选项?我正在使用MVVM框架将我的ViewModel绑定到我的View。
谢谢!

部分回答已经在https://dev59.com/anE85IYBdhLWcg3wx2n2#2615487中给出。 - Colonel Panic
4个回答

7
采用Bill的答案,将选项1和2合并,并添加一些附加属性作为编写代码后备方案,我想到了一个行为(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);

    }

}

然后我们在XAML中将其添加到数据网格中:

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

然后我们在ViewModel中编写RelayCommand:

    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);
    }

}

_resultsSelectedItems 是在 DataGrid 中显示的项目列表:
    Private _resultsSelectedItems As New List(Of WorkOrderMatchViewModel)

C#:

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

希望这可以帮到您,这种方法同时使用了Bill的两种方法,而不必引用MVVM-Light。

4

我也一直在寻找这个问题的答案。我发现的答案有两种方法:

1) 在代码后台委托工作到ViewModel中的一个方法,并传递DataGrid中的SelectedItems列表。该集合将包含所有已选项目。

或者

2) 使用MVVM toolkit light,它允许您使用事件转换为命令,并将对象直接作为参数传递到ViewModel。

private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    IList lst = this.myDataGrid.SelectedItems;
    ViewModel.RowsSelected(lst);
}

在这种情况下,您需要将xaml中的SelectionChanged绑定到代码后台中的selectionchanged。然后在代码后台中,您可以保存此列表并用于删除所选行等操作。
如果有更好的方法,请告诉我。
希望对您有所帮助。
Bill

3

C#版本的SelectedItemsBehavior类。可能会对某些人有所帮助。

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


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

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

    public static void OnSelectedItemsChangedHandlerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {

        DataGrid dataGrid = (DataGrid)d;

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

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


    public static void ItemsControl_SelectionChanged(Object sender, SelectionChangedEventArgs e)
    {

        DataGrid dataGrid = (DataGrid)sender;

        RelayCommand itemsChangedHandler = GetSelectedItemsChangedHandler(dataGrid);

        itemsChangedHandler.Execute(dataGrid.SelectedItems);
    }
}

2

我采用了Relay Commands(中继命令),就像Bill提到的那样,来解决这个问题。它在某些方面有些不太规范,但我避免了将任何代码放在后台文件中。

首先,在你的XAML中,将你的命令绑定在一个按钮上,或者绑定在任何触发你的RelayCommand的控件上。

<Button Content="Select" 
        cmd:ButtonBaseExtensions.Command="{Binding CommandSelect}"   
        cmd:ButtonBaseExtensions.CommandParameter="{Binding ElementName=Results, Path=SelectedItems}" />

你会注意到命令参数绑定到另一个UI元素 - 你想要获取选定项的DataGrid或ListView。这种语法在Silverlight3和WPF中都适用,因为它现在支持元素到元素的绑定。
在你的视图模型中,你的命令将类似于这样:
Private _CommandSelect As RelayCommand(Of IEnumerable)

Public ReadOnly Property CommandSelect() As RelayCommand(Of IEnumerable)
    Get
        If _CommandSelect Is Nothing Then
            _CommandSelect = New RelayCommand(Of IEnumerable)(AddressOf CommandSelectExecuted, AddressOf CommandSelectCanExecute)
        End If
        Return _CommandSelect
    End Get
End Property


Private Function CommandSelectExecuted(ByVal parameter As IEnumerable) As Boolean

    For Each Item As IElectoralAreaNode In parameter

    Next

    Return True
End Function

Private Function CommandSelectCanExecute() As Boolean
    Return True
End Function

所选项目将作为SelectedItemCollection返回,但您可能不希望在视图模型中出现这种依赖关系。因此,将其键入为IEnumerable并进行一些转换是您唯一的选择,这就是“肮脏”的原因。但它可以保持代码干净和MVVM模式完整!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接