从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
我会做这样的Binding
, i
是xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
和behaviors
是您的Behavior
类的命名空间
<ListBox> <i:Interaction.Behaviors> <behaviors:ListBoxSelectedItemsBehavior SelectedItems="{Binding SelectedItems, Mode=OneWayToSource}" /> </i:Interaction.Behaviors>
假设您的ListBox
的DataContext
在ViewModel
具有SelectedItems
属性,那么它将自动更新SelectedItems
。 你已经封装了从View
订阅的event
,
<ListBox SelectionChanged="ListBox_SelectionChanged"/>
如果需要,可以将Behavior
类更改为DataGrid
types。
我在我的应用中使用这个解决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。