9

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!

4

4 回答 4

7

以比尔的回答,合并选项 1 和 2,添加一些附加属性作为编写代码隐藏的替代方案,我想出了一个行为。

首先,我们有以下行为:

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

希望这会有所帮助,有点使用比尔的两种方法,而不必参考 MVVM-Light。

于 2011-06-07T19:29:34.373 回答
4

我也一直在寻找这个问题的答案。我找到的答案是

1) 在代码隐藏中将工作委托给 ViewModel 中的一个方法,该方法SelectedItems从数据网格传递列表。此集合将包含所有选定的项目。

或者

2) 使用 MVVM 工具包灯,它允许您使用 Event to Command 并将对象作为参数直接传递给 ViewModel。

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

在这种情况下,您需要将您SelectionChanged的 xaml 绑定到您selectionchanged在后面的代码中。然后在您的代码隐藏中,您可以保存此列表并将其用于删除选定的行等。

如果有更好的方法可以做到这一点,我很想知道。

高温高压

账单

于 2009-11-24T14:01:06.750 回答
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);
    }
}
于 2011-08-24T12:06:57.167 回答
2

正如比尔提到的,我设法使用中继命令解决了这个问题。部分有点脏,但我避免将任何代码放在后面的文件中。

首先,在您的 XAML 中 - 将您的命令绑定到一个按钮或任何触发您的 RelayCommand 的东西上。

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

您会注意到命令参数绑定到另一个 UI 元素 - 您希望从中获取所选项目的 DataGrid 或 ListView。此语法适用于 Silverlight 3 和 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 模式的机智!

于 2009-12-03T01:59:16.357 回答