将 ListView 的 SelectedItems 绑定到 ViewModel [英] Binding SelectedItems of ListView to ViewModel

查看:30
本文介绍了将 ListView 的 SelectedItems 绑定到 ViewModel的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个列表视图,该视图将项目与视图模型中的属性绑定.

I have a list view that binding items with a property in viewmodel.

<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的选中项?

How to get selected item of businesscollection in viewmodel?

推荐答案

1.源绑定的一种方法:

您必须使用 SelectionChanged 事件.最简单的方法是在代码隐藏中编写事件处理程序以绑定选定项"到视图模型.

You have to use SelectionChanged event. The easiest way is to write eventhandler in codebehind to "bind selecteditems" to viewmodel.

//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 设计一致,因为视图和视图模型的职责是分开的.您在代码隐藏中没有任何逻辑,并且视图模型干净且可测试.

This still aligns with MVVM design, because view and viewmodel resposibilities are kept separated. You dont have any logic in codebehind and viewmodel is clean and testable.

2.双向绑定:

如果你还需要更新视图,当视图模型改变时,你必须附加到视图模型的PropertyChanged 事件和所选项目的CollectionChanged 事件.当然你可以在代码隐藏中完成,但在这种情况下,我会创建一些更可重用的东西:

if you also need to update view, when viewmodel changes, you have to attach to ViewModel's PropertyChanged event and to the selected items' CollectionChanged event. of course you can do it in codebehind, but in this case I would create something more reusable:

//ViewModel
public ObservableCollection<YourBusinessItem> SelectedObject {get; set;}

//in codebehind:
var binder = new SelectedItemsBinder(listview, viewmodel.SelectedItems);
binder.Bind();

或者可以创建自定义附加属性,因此您可以在 xaml 中使用绑定语法:

or can create custom attached property, so you can use binding syntax in 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);
    }
}

这篇关于将 ListView 的 SelectedItems 绑定到 ViewModel的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆