8 ответов:
вы можете просто добавить пользовательские свойства зависимостей для этого:
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:<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такие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>предполагая, что ваш
DataContextнаListBoxимеетSelectedItemsсобственность в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"SelectedItemsCommand-это тип ICommand, который записан в вашем viewmodel.
используется DLL:
по умолчанию
DataGridиз WPF нельзя использовать привязку, как это возможно сSelectedItem-недвижимость, вызватьSelectedItems-свойство не является DependencyProperty.один из способов к тому, что вы хотите, чтобы зарегистрировать
SelectionChanged-событие 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<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>
вы можете maka a многоразовый универсальный базовый класс. Таким образом, вы можете выбрать строки как из кода, так и из пользовательского интерфейса.
это мой пример класса, который я хочу выбрать
public class MyClass { public string MyString {get; set;} }сделать общий базовый класс для выбираемых классов. INotifyPropertyChanged в делает обновление пользовательского интерфейса, когда вы устанавливаете изменили реализацию.
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; }создать выбираемый класс
public class MySelectableItem: SelectableItem<MyClass> { public MySelectableItem(MyClass item) :base(item) { } }создать свойство для привязки к
ObservableCollection<MySelectableItem> MyObservableCollection ...установить propety
MyObservableCollection = myItems.Select(x => new MySelectableItem(x));привязать к datagrid и добавить стиль на DataGridRow, который привязывается к IsSelected propety на MySelectedItem
<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);для выбора строк/пунктов
MyObservableCollection[0].IsSelected = true;правка---> Похоже, что это не работает, когда EnableRowVirtualization истинно
WPF DataGrid позволяет это. Просто установите DataGrid.Строки.SelectionMode и DataGrid.Строки.SelectionUnit в "Extended" и "CellOrRowHeader" соответственно. Это можно сделать в Blend, как показано на изображении, которое я включил. Это позволит пользователю выбрать каждой ячейки всех строк и т. д. столько, сколько им нравится, используя клавишу shift или ctrl для продолжения выбора.
проект, над которым я работаю, использует MVVM Light и я нашел этот блог пост чтобы быть самым простым решением. Я повторю решение здесь:
Модель Вид:
using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Command; ... public class SomeVm : ViewModelBase { public SomeVm() { SelectItemsCommand = new RelayCommand<IList>((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<SomeClass> Selected { get; set; } public RelayCommand<IList> SelectionChangedCommand { get; set; } public RelayCommand ViewCommand { get; set; } }XAML:
<Window ... xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:command="http://www.galasoft.ch/mvvmlight" ... <DataGrid Name="SomeGrid" ... <i:Interaction.Triggers> <i:EventTrigger EventName="SelectionChanged"> <command:EventToCommand Command="{Binding SelectionChangedCommand}" CommandParameter="{Binding SelectedItems, ElementName=SomeGrid}" /> </i:EventTrigger> </i:Interaction.Triggers> ... <DataGrid.ContextMenu> <ContextMenu> <MenuItem Header="View" Command="{Binding ViewCommand}" /> </ContextMenu> </DataGrid.ContextMenu> ...

Comments