繁体   English   中英

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

[英]How do I make binding work for a list property in a custom control?

由于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会很好。

这是因为SelectedItems的类型始终为System.Collections.IList {System.Windows.Controls.SelectedItemCollection} 因此,当您尝试使用IEnumerable您直接将SelectedItems分配给BindableSelectedItems 如果强制转换无效,并且将其发送为nullViewModel属性。

在那里,当您将类型设置为IEnumerable<string>您将已将SelectedItemsstring集合,例如BindableSelectedItems = SelectedItems.Cast<string>(); 它与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);
    }
}

视图模型

public class ViewModel
{
    public IEnumerable Items { get; set; }
    public IEnumerable SelectedItems { get; set; }

    public ViewModel()
    {
        Items = new List<string> { "Test", "Test1" };
        SelectedItems = new List<string> { "Test" };
    }
}

我已经测试了常见的情况,并且工作正常。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM