【问题标题】:Dynamically add item to ListBox whose DataSource is bound to a collection将项目动态添加到其 DataSource 绑定到集合的 ListBox
【发布时间】:2018-08-25 19:35:41
【问题描述】:

我正在尝试创建自定义的可重用 WPF UserControl,它具有一个列表框和一个用于添加新行的按钮,就像 DataGrid 允许用户添加新行一样。

此控件将绑定到各种视图模型中的许多不同类型的集合(即 List、ObservableCollection 等)。

我的 UserControl 具有一个名为 DataSource 的 IEnumerable 类型的依赖属性(它必须是 IEnumerable 才能允许 ObservableCollections、Lists 等)。我想为基础集合中的任何对象创建一个新实例,并将其添加到绑定到 ItemsSource 的原始集合中。

我创建了一个方法,该方法将创建集合所包含的对象的新实例:

private object GetNewItem()
{
    if (ItemsSource == null)
        throw new ArgumentException("ItemsSource not set");

    Type itemType = null;
    foreach (Type i in ItemsSource.GetType().GetInterfaces())
    {
        if (i.IsGenericType && i.GetGenericTypeDefinition().Equals(typeof(IEnumerable<>)))
            itemType = i.GetGenericArguments()[0];
    }

    if (itemType == null)
        throw new ArgumentException("Unable to get ItemsSource's Type T");

    return Activator.CreateInstance(itemType);
}

现在我只需要将新对象添加到原始集合中。不幸的是,IEnumerable 不允许添加项目,因为它不是可变的。

我可以检测出最初使用的是哪种类型的集合,即:

if (itemsType.IsGenericType && itemsType.GetGenericTypeDefinition() == typeof(ObservableCollection<>))

所以,我可以获得集合的类型,以及该集合的泛型类型(即,集合是“ObservableCollection”,泛型类型是“Person”),但我不知道如何将其转换回来。 ..即使可以,我也无法将 GetNewItem 的结果添加为:

((ObservableCollection<Person>) ItemsSource).Add(object) 

...如果不将对象转换为“Person”,则无法正常工作。

DataGrids 能够添加它的 ItemsSource 基础类型的新实例,即使它的 ItemsSource 是 IEnumerable,所以我知道这不是不可能的。我只是看不出如何使它工作。如有任何建议,我将不胜感激。

【问题讨论】:

    标签: c# wpf generics reflection


    【解决方案1】:

    DataGrid 借助基于 ItemsSource 的 IEditableCollectionView 视图添加新项目:参见 source code

    所以尝试将 ItemsSource 转换为 IEditableCollectionView 并添加新项目,而无需自己创建实例。

    var c = CollectionViewSource.GetDefaultView(ItemsSource) as IEditableCollectionView;
    if (c != null && c.CanAddNew)
        c.AddNew();
    

    但是,即使 List 有 Add 方法,此方法也不适用于 List&lt;DateTime&gt;:CanAddNew 为 false。也许是因为 DateTime 是一个不可变的结构。

    这个方法好像有限,我再试试:

    没有任何 IEnumerable 具有 Add 方法,该方法在 IList 接口中定义。如果 ItemsSource 不是 IList,那么如果没有关于具体类型的特殊知识,就无法添加任何内容。即使使用 IList 也不能​​保证添加(它可以是 ReadOnly 或 FixedSize (arrays, []))

    var c = ItemsSource as IList;
    if (c != null && !c.IsReadOnly && !c.IsFixedSize)
        c.Add(newInstance);
    

    【讨论】:

    • 抱歉耽搁了;生活让我暂时离开了工作。这非常有帮助,尤其是 datagrid.cs 代码的链接。感谢您提供的信息
    猜你喜欢
    • 1970-01-01
    • 2012-03-19
    • 2013-07-07
    • 1970-01-01
    • 2011-03-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-16
    • 1970-01-01
    相关资源
    最近更新 更多