WPF Select 来自具有双向绑定的 ViewModel 的 DataGrid 中的多个项目
WPF Select multiple items in DataGrid from ViewModel with twoway binding
我正在尝试创建双向绑定到 WPF DataGrid
中的 selected 项。我希望能够 select 来自 ViewModel
和实际 UserControl
的多个项目。我知道我不能直接设置 selected 项目,因为这个 属性 是只读的。
我正在考虑绑定到 DependencyProperty
并在后面的代码中订阅 DataGrid
的 SelectionChanged
事件。
<UserControl.Resources>
<Style TargetType="local:ListView">
<Setter Property="SelectedItems" Value="{Binding SelectedItemsVM, Mode=TwoWay}"/>
</Style>
</UserControl.Resources>
<DataGrid Name="ObjectListDataGrid" SelectionChanged="OnSelectionChanged">
在后面的代码中,我创建了 DependencyProperty
。设置后,我订阅了 CollectionChanged
事件。
public ObservableCollection<object> SelectedItems
{
get { return (ObservableCollection<object>)GetValue(SelectedItemsProperty); }
set { SetValue(SelectedItemsProperty, value); }
}
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(ObservableCollection<object>), typeof(ListView), new PropertyMetadata(default(ObservableCollection<object>), OnSelectedItemsChanged));
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var collection = e.NewValue as ObservableCollection<object>;
if (collection != null)
{
collection.CollectionChanged -= OnSelectedItemsCollectionChanged;
collection.CollectionChanged += OnSelectedItemsCollectionChanged;
}
}
我使用 EventHandler
到 SelectionChanged
事件 DataGrid
到 add/remove 集合中的项目。
private void OnSelectionChanged(object sender, SelectionChangedEventArgs args)
{
SelectedItems.Remove(args.RemovedItems);
SelectedItems.Add(args.AddedItems);
}
现在我想 select 集合更改时 OnSelectedItemsCollectionChanged
方法中需要的行。
private static void OnSelectedItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
foreach (DataGridRow row in ObjectListDataGrid.Rows())
{
if(ObjectListDataGrid.SelectedItems.Contains(row.Item))
row.IsSelected = true;
else
row.IsSelected = false;
}
}
问题:
由于 OnSelectedItemsCollectionChanged
方法是静态的,我无法访问 ObjectListDataGrid
。有什么办法可以克服这个问题,或者以不同的方式来解决这个问题?
为了完整起见,DataGrid.Rows()
方法是获取行列表的扩展方法:
public static IEnumerable<DataGridRow> Rows(this DataGrid grid)
{
var itemsSource = grid.ItemsSource as IEnumerable;
if (null == itemsSource) yield return null;
foreach (var item in itemsSource)
{
var row = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (null != row) yield return row;
}
}
您的 OnSelectedItemsCollectionChanged
方法不能是静态的。
将 OnSelectedItemsChanged
方法的 DependencyObject
参数转换为您的 ListView class。还要确保将处理程序与 SelectedItems
属性.
的旧值分离
private static void OnSelectedItemsChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var listView = (ListView)d;
var oldCollection = (INotifyCollectionChanged)e.OldValue;
var newCollection = (INotifyCollectionChanged)e.NewValue;
if (oldCollection != null)
{
oldCollection.CollectionChanged -= listView.OnSelectedItemsCollectionChanged;
}
if (newCollection != null)
{
newCollection.CollectionChanged += listView.OnSelectedItemsCollectionChanged;
}
}
private void OnSelectedItemsCollectionChanged(
object sender, NotifyCollectionChangedEventArgs e)
{
foreach (var row in ObjectListDataGrid.Rows())
{
row.IsSelected = ObjectListDataGrid.SelectedItems.Contains(row.Item);
}
}
我正在尝试创建双向绑定到 WPF DataGrid
中的 selected 项。我希望能够 select 来自 ViewModel
和实际 UserControl
的多个项目。我知道我不能直接设置 selected 项目,因为这个 属性 是只读的。
我正在考虑绑定到 DependencyProperty
并在后面的代码中订阅 DataGrid
的 SelectionChanged
事件。
<UserControl.Resources>
<Style TargetType="local:ListView">
<Setter Property="SelectedItems" Value="{Binding SelectedItemsVM, Mode=TwoWay}"/>
</Style>
</UserControl.Resources>
<DataGrid Name="ObjectListDataGrid" SelectionChanged="OnSelectionChanged">
在后面的代码中,我创建了 DependencyProperty
。设置后,我订阅了 CollectionChanged
事件。
public ObservableCollection<object> SelectedItems
{
get { return (ObservableCollection<object>)GetValue(SelectedItemsProperty); }
set { SetValue(SelectedItemsProperty, value); }
}
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(ObservableCollection<object>), typeof(ListView), new PropertyMetadata(default(ObservableCollection<object>), OnSelectedItemsChanged));
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var collection = e.NewValue as ObservableCollection<object>;
if (collection != null)
{
collection.CollectionChanged -= OnSelectedItemsCollectionChanged;
collection.CollectionChanged += OnSelectedItemsCollectionChanged;
}
}
我使用 EventHandler
到 SelectionChanged
事件 DataGrid
到 add/remove 集合中的项目。
private void OnSelectionChanged(object sender, SelectionChangedEventArgs args)
{
SelectedItems.Remove(args.RemovedItems);
SelectedItems.Add(args.AddedItems);
}
现在我想 select 集合更改时 OnSelectedItemsCollectionChanged
方法中需要的行。
private static void OnSelectedItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
foreach (DataGridRow row in ObjectListDataGrid.Rows())
{
if(ObjectListDataGrid.SelectedItems.Contains(row.Item))
row.IsSelected = true;
else
row.IsSelected = false;
}
}
问题:
由于 OnSelectedItemsCollectionChanged
方法是静态的,我无法访问 ObjectListDataGrid
。有什么办法可以克服这个问题,或者以不同的方式来解决这个问题?
为了完整起见,DataGrid.Rows()
方法是获取行列表的扩展方法:
public static IEnumerable<DataGridRow> Rows(this DataGrid grid)
{
var itemsSource = grid.ItemsSource as IEnumerable;
if (null == itemsSource) yield return null;
foreach (var item in itemsSource)
{
var row = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (null != row) yield return row;
}
}
您的 OnSelectedItemsCollectionChanged
方法不能是静态的。
将 OnSelectedItemsChanged
方法的 DependencyObject
参数转换为您的 ListView class。还要确保将处理程序与 SelectedItems
属性.
private static void OnSelectedItemsChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var listView = (ListView)d;
var oldCollection = (INotifyCollectionChanged)e.OldValue;
var newCollection = (INotifyCollectionChanged)e.NewValue;
if (oldCollection != null)
{
oldCollection.CollectionChanged -= listView.OnSelectedItemsCollectionChanged;
}
if (newCollection != null)
{
newCollection.CollectionChanged += listView.OnSelectedItemsCollectionChanged;
}
}
private void OnSelectedItemsCollectionChanged(
object sender, NotifyCollectionChangedEventArgs e)
{
foreach (var row in ObjectListDataGrid.Rows())
{
row.IsSelected = ObjectListDataGrid.SelectedItems.Contains(row.Item);
}
}