Выберите несколько элементов из DataGrid в проекте MVVM MVPM
Как выбрать несколько элементов из DataGrid
в MVVM проекте MVVM?
- Редактирование одного клика в WPF DataGrid
- Получать значения из * .resx-файлов в XAML
- Как применить правило пользовательской сортировки к WPF DataGrid?
- Стиль кнопки WPF C #
- Ошибка привязки элемента ElementName
- В WPF можно фильтровать CollectionViewSource без кода?
- Связывание видимости DataGridTextColumn
- Разница между SelectedItem, SelectedValue и SelectedValuePath
Вы можете просто добавить свойство пользовательской зависимости, чтобы сделать это:
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 }
Теперь вы можете использовать этот dataGrid
в XAML:
Моя ViewModel
:
public class MyViewModel : INotifyPropertyChanged { private static object _lock = new object (); private List _myModel; public IEnumerable 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 (); 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)
Вы можете создать class поведения примерно так
public class ListBoxSelectedItemsBehavior : Behavior { 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
– пространство имен вашего classа Behavior
Предполагая, что ваш DataContext
для ListBox
имеет свойство SelectedItems
в ViewModel
он автоматически обновит SelectedItems
. Вы заключили event
подписанное в View
,
Вы можете изменить class Behavior
на тип DataGrid
если хотите.
Я использую это решение в своем приложении:
XAML:
в верхней части вашего файла xaml, добавьте эту строку кода:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
SelectedItemsCommand – это тип ICommand, который написан в вашей модели viewmodel.
Используемая DLL:
System.Windows.Interactivity.dll
С помощью DataGrid
по умолчанию WPF невозможно использовать привязку, как это возможно при выборе SelectedItem
-Property, так как свойство SelectedItems
-Property не является DependencyProperty.
Один из способов сделать то, что вы хотите, – зарегистрировать SelectionChanged
-Event DataGrid, чтобы обновить свойство ViewModel, которое хранит выбранные элементы.
Свойство SelectedItems DataGrid имеет тип 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 selectedObjects = selected.OfType ().ToList(); MyViewModel.SelectedMyObjects = selectedObjects; }
XAML
Вы можете добавить свойство IsSelected в Model и добавить checkBox в строку.
Вы можете maka повторно использовать общий базовый class . Таким образом, вы можете выбирать строки как из кода, так и из пользовательского интерфейса .
Это мой примерный class, который я хочу выбрать
public class MyClass { public string MyString {get; set;} }
Создайте общий базовый class для выбираемых classов. INotifyPropertyChanged делает обновление пользовательского интерфейса при установке IsSelected.
public class SelectableItem : 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; }
Создать выбранный class
public class MySelectableItem: SelectableItem { public MySelectableItem(MyClass item) :base(item) { } }
Создать свойство для привязки к
ObservableCollection MyObservableCollection ...
Установите пропеты
MyObservableCollection = myItems.Select(x => new MySelectableItem(x));
Привяжите к datagrid и добавьте стиль в DataGridRow, который привязан к IsSelected propety на MySelectedItem
Чтобы получить выбранные строки / элементы
var selectedItems = MyObservableCollection.Where(x=>x.IsSelected).Select(y=>y.Item);
Чтобы выбрать строки / элементы
MyObservableCollection[0].IsSelected = true;
Редактировать —> Кажется, что это не работает, когда EnableRowVirtualization истинна
WPF DataGrid позволяет это. Просто установите DataGrid.Rows.SelectionMode и DataGrid.Rows.SelectionUnit в «Extended» и «CellOrRowHeader» соответственно. Это можно сделать в Blend, как показано на изображении, которое я включил. Это позволит пользователю выбирать каждую ячейку, целые строки и т. Д. Столько, сколько им нравится, используя клавишу shift или ctrl для продолжения выбора.
Проект, над которым я работаю, использует MVVM Light, и я нашел это сообщение в блоге самым простым решением. Я повторю решение здесь:
Модель:
using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Command; ... public class SomeVm : ViewModelBase { public SomeVm() { SelectItemsCommand = new RelayCommand((items) => { Selected.Clear(); foreach (var item in items) Selected.Add((SomeClass)item); }); ViewCommand = new RelayCommand(() => { foreach (var selected in Selected) { // todo do something with selected items } }); } public List Selected { get; set; } public RelayCommand SelectionChangedCommand { get; set; } public RelayCommand ViewCommand { get; set; } }
XAML:
... ...