5

How does ListCollectionView.AddNew determine the type of object it creates, and how could one affect it?

I have a hierarchy of a few types (Base, DerivedA, and DerivedB), and currently my WPF Toolkit DataGrid creates DerivedA objects (why, I don't know -- probably because almost all the data in the grid is of that type), but I'd like it to create DerivedB objects instead.

Update: I've tried deriving a new class from ListCollectionView and implementing a new AddNew method for it, and now I'm almost there: the only remaining problem is that after adding a new item, a new new item placeholder isn't added, so I can only add one item. My current approach looks somewhat like this:

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;
    }
}
4

3 回答 3

4

陈旧的问题值得新的答案:)

派生一个类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; 
}

在这里,我将源代码包含在 my中,当我不知道在设计时需要什么类型时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我喜欢这种方法,因为它为's 类型可能需要在运行时从一个调整到另一个的情况提供了最大的灵活性。它还允许AddNew添加集合中的第一项,这在列表源最初为空时很方便,但可以确定其基础类型。

此链接讨论了强制使用的类型的另一种方法AddNew()。它使用反射将私有_itemConstructor属性设置AddNew为指定类型的无参数构造函数。当您来自不受您影响的组件时,这将特别有用ListCollectionView,或者您需要在现有代码中添加功能并且您担心会破坏某些东西(我从来没有这样做,因为我是一个冷酷无情的骑士编码员与收藏)。

于 2012-01-30T00:42:29.507 回答
2

在 .NET 4 中,现在有一个IEditableCollectionViewAddNewItem由 实现的新接口ListCollectionView,它拥有一个新方法AddNewItem(object)。您可以使用它来代替AddNew()控制新添加的项目。

于 2012-05-13T13:04:09.797 回答
1

TomiJ,

see if it helps, but isn't the answer ok?

http://www.cnblogs.com/winkingzhang/archive/2008/05/22/1204581.html

于 2009-05-08T20:30:44.893 回答