从MVVM WPF项目中的DataGrid中select多个项目

如何从MVVM WPF项目中的DataGrid中select多个项目?

你可以简单地添加一个自定义的依赖项属性来做到这一点:

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

我希望这个干净的MVVMdevise帮助。

我会做的是使用System.Windows.Interactivity创buildBehaviors 。 你将不得不在你的项目中手动引用它。

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

你可以创build一个像这样的行为类

 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我会做这样的Bindingixmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"behaviors是您的Behavior类的命名空间

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

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

 <ListBox SelectionChanged="ListBox_SelectionChanged"/> 

如果需要,可以将Behavior类更改为DataGridtypes。

我在我的应用中使用这个解决scheme:

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" 

SelectedItemsCommand是写在你的视图模型中的ICommandtypes。

使用DLL:

System.Windows.Interactivity.dll

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

一种方法到你想要的是注册SelectionChanged – DataGrid事件来更新您的ViewModel,存储所选项目的属性。

DataGrid的SelectedItems属性是IListtypes的,因此您需要将列表中的项目转换为您的特定types。

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> 

你可以做一个可重用的generics基类 。 这样你就可以从代码和UI中select行。

这是我希望可以select的示例类

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

为可选类创buildgenerics基类。 当您设置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 { if (value == _isSelected) { return; } _isSelected = value; if (PropertyChanged != null) { PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs("IsSelected")); } } } public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; } 

创build可select的类

 public class MySelectableItem: SelectableItem<MyClass> { public MySelectableItem(MyClass item) :base(item) { } } 

创build要绑定的属性

 ObservableCollection<MySelectableItem> MyObservableCollection ... 

设置propety

 MyObservableCollection = myItems.Select(x => new MySelectableItem(x)); 

绑定到DataGrid并在DataGridRow上添加一个绑定到MySelectedItem上的IsSelected属性的样式

 <DataGrid ItemsSource="{Binding MyObservableCollection}" SelectionMode="Extended"> <DataGrid.Resources> <Style TargetType="DataGridRow"> <Setter Property="IsSelected" Value="{Binding IsSelected}" /> </Style> </DataGrid.Resources> </DataGrid> 

获取选定的行/项目

 var selectedItems = MyObservableCollection.Where(x=>x.IsSelected).Select(y=>y.Item); 

select行/项目

 MyObservableCollection[0].IsSelected = true; 

WPF DataGrid允许这样做。 只需将DataGrid.Rows.SelectionMode和DataGrid.Rows.SelectionUnit分别设置为“Extended”和“CellOrRowHeader”即可。 这可以在Blend中完成,如图所示。 这将允许用户select每个单元格,整个行等,尽可能多的使用shift或ctrl键继续select。 在这里输入图像描述

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