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

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

问题描述

我在使用棱镜的 SL3 应用程序中有一个多选列表框,我需要在我的视图模型中有一个集合,其中包含列表框中当前选定的项目.

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.

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

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.

不知道如何解决这个问题

Not sure how to approach this problem

谢谢迈克尔

推荐答案

因此,假设您有一个具有以下属性的 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);
        }
    }
}

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

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