如何在自定义控件中对列表属性进行绑定工作?

时间:2018-07-10 16:01:28

标签: c# wpf data-binding listbox

由于ListBox不允许您双向绑定到其SelectedItems属性,因此我创建了自己的自定义控件MultipleSelectionListBox。它添加了属性BindableSelectedItems,可让您将IEnumerable绑定到该属性。

public class MultipleSelectionListBox : ListBox
{
    public static readonly DependencyProperty BindableSelectedItemsProperty =
        DependencyProperty.Register("BindableSelectedItems",
            typeof(IEnumerable), typeof(MultipleSelectionListBox),
            new FrameworkPropertyMetadata(default(IEnumerable),
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnBindableSelectedItemsChanged));

    public IEnumerable BindableSelectedItems
    {
        get => (IEnumerable)GetValue(BindableSelectedItemsProperty);
        set => SetValue(BindableSelectedItemsProperty, value);
    }

    protected override void OnSelectionChanged(SelectionChangedEventArgs e)
    {
        base.OnSelectionChanged(e);
        BindableSelectedItems = SelectedItems;
    }

    private static void OnBindableSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is MultipleSelectionListBox listBox)
            listBox.SetSelectedItems(listBox.BindableSelectedItems);
    }
}

我要绑定到的视图模型的属性的类型为IEnumerable<string>,并且绑定不起作用。更改列表框的选择后,视图模型的属性始终会收到null

如果我将BindableSelectedItems的类型更改为IEnumerable<string>,则绑定有效。这使我相信绑定不喜欢类型不匹配。我是否必须明确指定列表项的类型,还是可以保持列表的一般性?能够将相同的MultipleSelectionListBox用于其他类型的项目会很好。

1 个答案:

答案 0 :(得分:1)

这是因为SelectedItems将始终为System.Collections.IList {System.Windows.Controls.SelectedItemCollection}类型。因此,当您尝试使用IEnumerable时,您是直接将SelectedItems分配给BindableSelectedItems。在强制转换无效的情况下,它已null发送到您的ViewModel属性。

当您将类型设置为IEnumerable<string>时,您会将SelectedItems强制转换为string之类的BindableSelectedItems = SelectedItems.Cast<string>();集合,该集合与{{ 1}}并有效。

我看到您想使其通用。为此,您可以尝试类似的

列表框控件代码

ViewModel

ViewModel

public class MultipleSelectionListBox : ListBox
{
    public static readonly DependencyProperty BindableSelectedItemsProperty =
        DependencyProperty.Register("BindableSelectedItems",
            typeof(IList), typeof(MultipleSelectionListBox),
            new FrameworkPropertyMetadata(default(IList),
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnBindableSelectedItemsChanged));

    public IList BindableSelectedItems
    {
        get => (IList)GetValue(BindableSelectedItemsProperty);
        set => SetValue(BindableSelectedItemsProperty, value);
    }

    protected override void OnSelectionChanged(SelectionChangedEventArgs e)
    {
        base.OnSelectionChanged(e);

        IList selectedItemsList = BindableSelectedItems;
        if (selectedItemsList == null)
            selectedItemsList = (IList)Activator.CreateInstance(ItemsSource.GetType());
        selectedItemsList.Clear();

        foreach (var item in SelectedItems)
            selectedItemsList.Add(item);

        BindableSelectedItems = selectedItemsList;
    }

    private static void OnBindableSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is MultipleSelectionListBox listBox)
            listBox.SetSelectedItems(listBox.BindableSelectedItems);
    }
}

我已经在常见情况下进行了测试,并且工作正常。