ListCollectionView.AddNew 创建的对象类型

发布于 2024-07-19 01:15:28 字数 795 浏览 5 评论 0原文

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

套路撩心 2024-07-26 01:15:28

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

ListCollectionView 派生一个类也是我用来控制由 AddNew 添加的对象的路径,但在浏览 的源代码之后code>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 来添加集合中的第一项,这在列表源最初为空但可以确定其基础类型时很方便。

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

Stale questions deserve fresh answers :)

Deriving a class from ListCollectionView is the path I took to control the objects being added by AddNew as well, but after browsing through the source of ListCollectionView to find out what it does internally, I found that the safest way to redefine AddNew (it's not technically an override) is to use ListCollectionView.AddNewItem after creating my new object, so your code would look like this:

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

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

This works well because, in addition to having nearly identical implementations otherwise, ListCollectionView.AddNew() and ListCollectionView.AddNewItem(object item) both call 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 is where all the real magic happens; firing events, calling BeginInit and BeginEdit on the new item if supported, and eventually through callbacks on the datagrid, establishing the cell bindings:

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

Here I've included the source code to my TypedListCollectionView, which I use to control the AddNew behavior when I don't know what type will be needed at design time:

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

I like this approach since it provides maximum flexibility for cases where AddNew's type may need to be adjusted at runtime from one to another. It also allows AddNew to work for adding the first item in the collection, which is handy when the list source is initially empty, but its underlying type can be determined.

This link discusses an alternative way to force the type used by AddNew(). It uses reflection to set the private _itemConstructor property used by AddNew to a parameterless constructor of a specified type. This would be particularly useful when your ListCollectionView is coming from a component that's outside of your influence, or you need to add functionality into existing code and you're worried about breaking things (which I never am because I'm a cavalier coder who callously carouses with collections).

过去的过去 2024-07-26 01:15:28

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

In .NET 4, there is now a new interface IEditableCollectionViewAddNewItem, implemented by ListCollectionView, which possesses a new method AddNewItem(object). You can use it instead of AddNew() to control the newly added item.

短暂陪伴 2024-07-26 01:15:28

TomiJ,

看看是否有帮助,但答案不是很好吗?

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

TomiJ,

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文