将 ListView 的 SelectedItems 绑定到 ViewModel
Posted
技术标签:
【中文标题】将 ListView 的 SelectedItems 绑定到 ViewModel【英文标题】:Binding SelectedItems of ListView to ViewModel 【发布时间】:2021-09-23 20:06:16 【问题描述】:我有一个列表视图,它将项目与视图模型中的属性绑定。
<ListView Height="238"
HorizontalAlignment="Left"
Name="listView"
VerticalAlignment="Top"
Width="503"
ItemsSource="Binding BusinessCollection"
SelectionMode="Multiple">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="Binding RelativeSource=RelativeSource AncestorType=x:Type ListViewItem, Path=IsSelected" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="Binding ID" Header="ID" />
<GridViewColumn DisplayMemberBinding="Binding Name" Header="Name" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
在视图模型中。
ICollectionView _businessCollection
public ICollectionView BusinessCollection
get return _businessCollection;
set
_businessCollection = value;
RaisePropertyOnChange("BusinessCollection");
如何在viewmodel中获取businesscollection的选中项?
【问题讨论】:
【参考方案1】:1.一种源绑定方式:
您必须使用SelectionChanged
事件。最简单的方法是在代码隐藏中编写事件处理程序以将选定项“绑定”到视图模型。
//ViewModel
public ICollectionView BusinessCollection get; set;
public List<YourBusinessItem> SelectedObject get; set;
//Codebehind
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
var viewmodel = (ViewModel) DataContext;
viewmodel.SelectedItems = listview.SelectedItems
.Cast<YourBusinessItem>()
.ToList();
这仍然符合 MVVM 设计,因为视图和视图模型的职责是分开的。您在代码隐藏中没有任何逻辑,并且视图模型是干净且可测试的。
2。两种方式绑定:
如果您还需要更新视图,当视图模型更改时,您必须附加到 ViewModel 的 PropertyChanged
事件和选定项的 CollectionChanged
事件。当然你可以在代码隐藏中做到这一点,但在这种情况下,我会创建一些更可重用的东西:
//ViewModel
public ObservableCollection<YourBusinessItem> SelectedObject get; set;
//in codebehind:
var binder = new SelectedItemsBinder(listview, viewmodel.SelectedItems);
binder.Bind();
或者可以创建自定义附加属性,因此您可以在 xaml 中使用绑定语法:
<ListView local:ListViewExtensions.SelectedValues="Binding SelectedItem" .../>
public class SelectedItemsBinder
private ListView _listView;
private IList _collection;
public SelectedItemsBinder(ListView listView, IList collection)
_listView = listView;
_collection = collection;
_listView.SelectedItems.Clear();
foreach (var item in _collection)
_listView.SelectedItems.Add(item);
public void Bind()
_listView.SelectionChanged += ListView_SelectionChanged;
if (_collection is INotifyCollectionChanged)
var observable = (INotifyCollectionChanged) _collection;
observable.CollectionChanged += Collection_CollectionChanged;
public void UnBind()
if (_listView != null)
_listView.SelectionChanged -= ListView_SelectionChanged;
if (_collection != null && _collection is INotifyCollectionChanged)
var observable = (INotifyCollectionChanged) _collection;
observable.CollectionChanged -= Collection_CollectionChanged;
private void Collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
foreach (var item in e.NewItems ?? new object[0])
if (!_listView.SelectedItems.Contains(item))
_listView.SelectedItems.Add(item);
foreach (var item in e.OldItems ?? new object[0])
_listView.SelectedItems.Remove(item);
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
foreach (var item in e.AddedItems ?? new object[0])
if (!_collection.Contains(item))
_collection.Add(item);
foreach (var item in e.RemovedItems ?? new object[0])
_collection.Remove(item);
附加属性实现
public class ListViewExtensions
private static SelectedItemsBinder GetSelectedValueBinder(DependencyObject obj)
return (SelectedItemsBinder)obj.GetValue(SelectedValueBinderProperty);
private static void SetSelectedValueBinder(DependencyObject obj, SelectedItemsBinder items)
obj.SetValue(SelectedValueBinderProperty, items);
private static readonly DependencyProperty SelectedValueBinderProperty = DependencyProperty.RegisterAttached("SelectedValueBinder", typeof(SelectedItemsBinder), typeof(ListViewExtensions));
public static readonly DependencyProperty SelectedValuesProperty = DependencyProperty.RegisterAttached("SelectedValues", typeof(IList), typeof(ListViewExtensions),
new FrameworkPropertyMetadata(null, OnSelectedValuesChanged));
private static void OnSelectedValuesChanged(DependencyObject o, DependencyPropertyChangedEventArgs value)
var oldBinder = GetSelectedValueBinder(o);
if (oldBinder != null)
oldBinder.UnBind();
SetSelectedValueBinder(o, new SelectedItemsBinder((ListView)o, (IList)value.NewValue));
GetSelectedValueBinder(o).Bind();
public static void SetSelectedValues(Selector elementName, IEnumerable value)
elementName.SetValue(SelectedValuesProperty, value);
public static IEnumerable GetSelectedValues(Selector elementName)
return (IEnumerable)elementName.GetValue(SelectedValuesProperty);
【讨论】:
非常感谢,对我帮助很大:) 感谢您的代码。您还应该在 Collection_CollectionChanged 方法中处理集合重置。 您可能编写了混淆代码,认为您的类名是 ListViewXxx 但实现是 ListBoxXxx。 我在 CollectionChanged 方法中添加了对 Reset 的处理。【参考方案2】:由于 itemSource 是 BusinessCollection,您应该能够:
var selectedItems = BusinessCollection.Where(x => x.IsSelected);
将其包装为 VM 上的属性。 希望对您有所帮助!
【讨论】:
谢谢,但 BusinessCollection 没有 IsSelected 属性。 抱歉没有检查。为什么不使用不同的集合呢?使用 ObservableCollection,我知道它可以工作,因为我之前已经实现过它。 这与绑定无关。以上是关于将 ListView 的 SelectedItems 绑定到 ViewModel的主要内容,如果未能解决你的问题,请参考以下文章
UI响应性并使用WPF中的“SelectedItem”ListView / ListBox
WPF ListView 忽略 SelectedItem-change
绑定到 ListView 的 SelectedItem 属性时设置初始选定项