从MVVM WPF项目中的DataGrid中选择多个项目

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从MVVM WPF项目中的DataGrid中选择多个项目相关的知识,希望对你有一定的参考价值。

如何在MVVM WPF项目中从DataGrid中选择多个项目?

答案

您只需添加自定义依赖项属性即可:

public class CustomDataGrid : DataGrid
{
    public CustomDataGrid ()
    {
        this.SelectionChanged += CustomDataGrid_SelectionChanged;
    }

    void CustomDataGrid_SelectionChanged (object sender, SelectionChangedEventArgs e)
    {
        this.SelectedItemsList = this.SelectedItems;
    }
    #region SelectedItemsList

    public IList SelectedItemsList
    {
        get { return (IList)GetValue (SelectedItemsListProperty); }
        set { SetValue (SelectedItemsListProperty, value); }
    }

    public static readonly DependencyProperty SelectedItemsListProperty =
            DependencyProperty.Register ("SelectedItemsList", typeof (IList), typeof (CustomDataGrid), new PropertyMetadata (null));

    #endregion
}

现在你可以在XAML中使用这个dataGrid

<Window x:Class="DataGridTesting.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:local="clr-namespace:DataGridTesting.CustomDatagrid"
    Title="MainWindow"
    Height="350"
    Width="525">
  <DockPanel>
    <local:CustomDataGrid ItemsSource="{Binding Model}"
        SelectionMode="Extended"
        AlternatingRowBackground="Aquamarine"
        SelectionUnit="FullRow"
        IsReadOnly="True"
        SnapsToDevicePixels="True"
        SelectedItemsList="{Binding TestSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
  </DockPanel>
</Window>

我的ViewModel

public class MyViewModel : INotifyPropertyChanged
{
    private static object _lock = new object ();
    private List<MyModel> _myModel;

    public IEnumerable<MyModel> Model { get { return _myModel; } }

    private IList _selectedModels = new ArrayList ();

    public IList TestSelected
    {
        get { return _selectedModels; }
        set
        {
            _selectedModels = value;
            RaisePropertyChanged ("TestSelected");
        }
    }

    public MyViewModel ()
    {
        _myModel = new List<MyModel> ();
        BindingOperations.EnableCollectionSynchronization (_myModel, _lock);

        for (int i = 0; i < 10; i++)
        {
            _myModel.Add (new MyModel
            {
                Name = "Test " + i,
                Age = i * 22
            });
        }
        RaisePropertyChanged ("Model");
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged (string propertyName)
    {
        var pc = PropertyChanged;
        if (pc != null)
            pc (this, new PropertyChangedEventArgs (propertyName));
    }
}

我的模特:

public class MyModel
{
    public string Name { get; set; }
    public int Age { get; set; }
}

最后,这是MainWindow背后的代码:

public partial class MainWindow : Window
{
    public MainWindow ()
    {
        InitializeComponent ();
        this.DataContext = new MyViewModel ();
    }
}

我希望这个干净的MVVM设计有所帮助。

另一答案

我要做的是使用Behaviors创建System.Windows.Interactivity。您必须在项目中手动引用它。

给定一个不暴露SelectedItems的控件,例如,(ListBox,DataGrid)

您可以创建类似这样的行为类

public class ListBoxSelectedItemsBehavior : Behavior<ListBox>
{
    protected override void OnAttached()
    {
        AssociatedObject.SelectionChanged += AssociatedObjectSelectionChanged;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.SelectionChanged -= AssociatedObjectSelectionChanged;
    }

    void AssociatedObjectSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var array = new object[AssociatedObject.SelectedItems.Count];
        AssociatedObject.SelectedItems.CopyTo(array, 0);
        SelectedItems = array;
    }

    public static readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.Register("SelectedItems", typeof(IEnumerable), typeof(ListBoxSelectedItemsBehavior), 
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public IEnumerable SelectedItems
    {
        get { return (IEnumerable)GetValue(SelectedItemsProperty); }
        set { SetValue(SelectedItemsProperty, value); }
    }
}

在你的XAML我会像这样做Binding ixmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"behaviors是你的Behavior类的命名空间

<ListBox>
 <i:Interaction.Behaviors>
    <behaviors:ListBoxSelectedItemsBehavior SelectedItems="{Binding SelectedItems, Mode=OneWayToSource}" />
 </i:Interaction.Behaviors>

假设你的DataContextListBoxSelectedItems中具有ViewModel属性,那么它将自动更新SelectedItems。你已经封装了从event订阅的View,即

<ListBox SelectionChanged="ListBox_SelectionChanged"/>

如果需要,您可以将Behavior类更改为DataGrid类型。

另一答案

我在我的应用中使用此解决方案:

XAML:

<i:Interaction.Triggers>
     <i:EventTrigger EventName="SelectionChanged">
         <i:InvokeCommandAction Command="{Binding SelectItemsCommand}" CommandParameter="{Binding Path=SelectedItems,ElementName=TestListView}"/>
     </i:EventTrigger>
</i:Interaction.Triggers>

在你的xaml文件的顶部,添加以下代码行:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

SelectedItems命令是在视图模型中编写的命令类型。

使用的DLL:

System.Windows.Interactivity.dll

另一答案

使用WPF的默认DataGrid,不可能使用绑定,因为SelectedItem-Property可能导致SelectedItems-Property不是DependencyProperty。

实现目标的一种方法是注册DataGrid的SelectionChanged-Event以更新存储所选项的ViewModel的属性。

DataGrid的属性SelectedItems属于IList类型,因此您需要将列表中的项目转换为您的特定类型。

C#

public MyViewModel {
  get{
    return this.DataContext as MyViewModel;
  }
}

private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) {
  // ... Get SelectedItems from DataGrid.
  var grid = sender as DataGrid;
  var selected = grid.SelectedItems;

  List<MyObject> selectedObjects = selected.OfType<MyObject>().ToList();

  MyViewModel.SelectedMyObjects = selectedObjects;
}

XAML

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
    <DataGrid
        SelectionChanged="DataGrid_SelectionChanged"
        />
    </Grid>
</Window>
另一答案

您可以在模型中添加“IsSelected”属性,并在行中添加一个复选框。

另一答案

您可以创建可重用的通用基类。这样,您可以从代码和UI中选择行。

这是我希望可以选择的示例类

public class MyClass
{
    public string MyString {get; set;}   
}

为可选类创建通用基类。设置IsSelected时,INotifyPropertyChanged会更新UI。

public class SelectableItem<T> : System.ComponentModel.INotifyPropertyChanged
{
    public SelectableItem(T item)
    {
        Item = item;
    }

    public T Item { get; set; }

    bool _isSelected;

    public bool IsSelected {
        get {
            return _isSelected;
        }
        set {
      

以上是关于从MVVM WPF项目中的DataGrid中选择多个项目的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 MVVM 自动隐藏 WPF 中的 DataGrid 列? [复制]

WPF DataGrid Multiselect启用了虚拟化MVVM

如何防止 WPF DataGrid 在项目更新时取消选择 SelectedItem?

WPF MVVM 将 ComboBox 绑定到 Datagrid 选定项

在 MVVM 中的 Datagrid 中绑定 WPF 组合框不保存更改

如何取消选择 DataGrid 中的所有项目?