将多选择列表框中的SelectedItem与ViewModel中的集合同步 [英] Sync SelectedItems in a muliselect listbox with a collection in ViewModel

查看:109
本文介绍了将多选择列表框中的SelectedItem与ViewModel中的集合同步的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用棱镜的SL3应用程序中有一个多选列表框,并且我的viewmodel中需要一个包含列表框中当前选定项的集合.

I have a multi-select listbox in a SL3 app using prism and I need a collection in my viewmodel that contains the currently selected items in the listbox.

viewmodel对视图一无所知,因此无法访问列表框控件.另外,我还需要能够从视图模型中清除列表框中的选定项目.

The viewmodel doesn't know anything about the view so it does not have access to the listbox control. Also I need to be able to clear the selected items in the listbox from the viewmodel.

不确定如何解决此问题

谢谢 迈克尔

推荐答案

因此,假设您具有一个具有以下属性的ViewModel:

So, assume you have a ViewModel with the following properties:

public ObservableCollection<string> AllItems { get; private set; }
public ObservableCollection<string> SelectedItems { get; private set; }

首先将AllItems集合绑定到ListBox:

You would start by binding your AllItems collection to the ListBox:

<ListBox x:Name="MyListBox" ItemsSource="{Binding AllItems}" SelectionMode="Multiple" />

问题在于ListBox上的SelectedItems属性不是DependencyProperty.这很糟糕,因为您无法将其绑定到ViewModel中的某个对象上.

The problem is that the SelectedItems property on ListBox is not a DependencyProperty. This is pretty bad, since you can't bind it to something in your ViewModel.

第一种方法是将这种逻辑放在后面的代码中,以调整ViewModel:

The first approach is to just put this logic in the code-behind, to tweak the ViewModel:

public MainPage()
{
    InitializeComponent();

    MyListBox.SelectionChanged += ListBoxSelectionChanged;
}

private static void ListBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var listBox = sender as ListBox;
    if(listBox == null) return;

    var viewModel = listBox.DataContext as MainVM;
    if(viewModel == null) return;

    viewModel.SelectedItems.Clear();

    foreach (string item in listBox.SelectedItems)
    {
        viewModel.SelectedItems.Add(item);
    }
}

这种方法行得通,但是确实很丑陋.我的首选方法是将这种行为提取到附加行为"中.如果这样做,则可以完全消除代码隐藏,并在XAML中进行设置.好处是,此附加行为"现在可以在任何ListBox中重新使用:

This approach will work, but it is really ugly. My preferred approach is to extract this behavior into an "Attached Behavior". If you do that, you can completely eliminate your code-behind and set it up in the XAML. The bonus is that this "Attached Behavior" is now re-usable in any ListBox:

<ListBox ItemsSource="{Binding AllItems}" Demo:SelectedItems.Items="{Binding SelectedItems}" SelectionMode="Multiple" />

这是附加行为的代码:

public static class SelectedItems
{
    private static readonly DependencyProperty SelectedItemsBehaviorProperty =
        DependencyProperty.RegisterAttached(
            "SelectedItemsBehavior",
            typeof(SelectedItemsBehavior),
            typeof(ListBox),
            null);

    public static readonly DependencyProperty ItemsProperty = DependencyProperty.RegisterAttached(
            "Items",
            typeof(IList),
            typeof(SelectedItems),
            new PropertyMetadata(null, ItemsPropertyChanged));

    public static void SetItems(ListBox listBox, IList list) { listBox.SetValue(ItemsProperty, list); }
    public static IList GetItems(ListBox listBox) { return listBox.GetValue(ItemsProperty) as IList; }

    private static void ItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = d as ListBox;
        if (target != null)
        {
            GetOrCreateBehavior(target, e.NewValue as IList);
        }
    }

    private static SelectedItemsBehavior GetOrCreateBehavior(ListBox target, IList list)
    {
        var behavior = target.GetValue(SelectedItemsBehaviorProperty) as SelectedItemsBehavior;
        if (behavior == null)
        {
            behavior = new SelectedItemsBehavior(target, list);
            target.SetValue(SelectedItemsBehaviorProperty, behavior);
        }

        return behavior;
    }
}

public class SelectedItemsBehavior
{
    private readonly ListBox _listBox;
    private readonly IList _boundList;

    public SelectedItemsBehavior(ListBox listBox, IList boundList)
    {
        _boundList = boundList;
        _listBox = listBox;
        _listBox.SelectionChanged += OnSelectionChanged;
    }

    private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        _boundList.Clear();

        foreach (var item in _listBox.SelectedItems)
        {
            _boundList.Add(item);
        }
    }
}

这篇关于将多选择列表框中的SelectedItem与ViewModel中的集合同步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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