ListCollectionView.AddNew如何确定它创建的对象的类型,以及如何影响它?

我有一些类型的层次结构(BaseDerivedADerivedB),当前我的WPF工具包DataGrid创建DerivedA对象(为什么,我不知道-可能是因为几乎所有网格中的数据属于该类型),但我想改为创建DerivedB对象。

更新:我已经尝试从ListCollectionView派生一个新类并为其实现一个新的AddNew方法,现在我已经差不多了:唯一剩下的问题是在添加新项目之后,新的新项目占位符没有添加,所以我只能添加一项​​。我当前的方法看起来像这样:

public class CustomView : ListCollectionView, IEditableCollectionView
{
    public CustomView(System.Collections.IList list)
        : base(list)
    {
    }

    object IEditableCollectionView.AddNew()
    {
        DerivedB obj = new DerivedB();
        InternalList.Add(obj);
        return obj;
    }
}

最佳答案

过时的问题值得重新回答:)

ListCollectionView派生一个类也是我控制AddNew所添加对象的路径,但是在浏览ListCollectionView的源代码以了解其内部作用之后,我发现最安全的方法是重新定义AddNew(从技术上讲,这不是一个替代)是在创建新对象后使用ListCollectionView.AddNewItem,因此您的代码如下所示:

public class CustomView : ListCollectionView, IEditableCollectionView
{
    public CustomView(System.Collections.IList list)
        : base(list)
    {
    }

    object IEditableCollectionView.AddNew()
    {
        DerivedB obj = new DerivedB();
        return base.AddNewItem(obj);
    }
}


之所以行之有效,是因为除了具有几乎相同的实现之外,ListCollectionView.AddNew()ListCollectionView.AddNewItem(object item)都调用AddNewCommon(object newItem)

public object AddNew()
{
    VerifyRefreshNotDeferred();

    if (IsEditingItem)
        CommitEdit();   // implicitly close a previous EditItem

    CommitNew();        // implicitly close a previous AddNew

    if (!CanAddNew)
        throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "AddNew"));

    return AddNewCommon(_itemConstructor.Invoke(null));
}

public object AddNewItem(object newItem)
{
    VerifyRefreshNotDeferred();

    if (IsEditingItem)
        CommitEdit();   // implicitly close a previous EditItem

    CommitNew();        // implicitly close a previous AddNew

    if (!CanAddNewItem)
        throw new InvalidOperationException(SR.Get(SRID.MemberNotAllowedForView, "AddNewItem"));

    return AddNewCommon(newItem);
}


AddNewCommon是所有真正的魔术发生的地方;触发事件,如果支持,则在新项目上调用BeginInitBeginEdit,最终通过数据网格上的回调,建立单元绑定:

object AddNewCommon(object newItem)
{
    _newItemIndex = -2; // this is a signal that the next Add event comes from AddNew
    int index = SourceList.Add(newItem);

    // if the source doesn't raise collection change events, fake one
    if (!(SourceList is INotifyCollectionChanged))
    {
        // the index returned by IList.Add isn't always reliable
        if (!Object.Equals(newItem, SourceList[index]))
            index = SourceList.IndexOf(newItem);

        BeginAddNew(newItem, index);
    }

    Debug.Assert(_newItemIndex != -2 && Object.Equals(newItem, _newItem), "AddNew did not raise expected events");

    MoveCurrentTo(newItem);

    ISupportInitialize isi = newItem as ISupportInitialize;
    if (isi != null)
        isi.BeginInit();

    IEditableObject ieo = newItem as IEditableObject;
    if (ieo != null)
        ieo.BeginEdit();

    return newItem;
}


在这里,我已经将源代码包含到我的TypedListCollectionView中,当我不知道在设计时需要哪种类型时,可以使用它来控制AddNew行为:

public class TypedListCollectionView : ListCollectionView, IEditableCollectionView
{
    Type AddNewType { get; set; }

    public TypedListCollectionView(System.Collections.IList source, Type addNewType)
        : base(source)
    {
        AddNewType = addNewType;
    }

    object IEditableCollectionView.AddNew()
    {
        object newItem = Activator.CreateInstance(AddNewType);
        return base.AddNewItem(newItem);
    }
}


我喜欢这种方法,因为它在需要在运行时将AddNew的类型从一个调整到另一个的情况下提供了最大的灵活性。它还允许AddNew用于添加集合中的第一项,这在列表源最初为空时很方便,但是可以确定其基础类型。

This link讨论了强制使用AddNew()使用的类型的另一种方法。它使用反射将_itemConstructor使用的私有AddNew属性设置为指定类型的无参数构造函数。当您的ListCollectionView来自不受您影响的组件时,或者您需要在现有代码中添加功能并且担心出现问题时,这将特别有用(我从来都不是因为我是一名勇敢的编码员那些无情地收藏的人)。

07-26 03:54