ListCollectionView.AddNew
如何确定它创建的对象的类型,以及如何影响它?
我有几种类型的层次结构(Base
,DerivedA
和DerivedB
),目前我的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;
}
}
答案 0 :(得分: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
是所有真正的魔法发生的地方;触发事件,如果支持,则在新项目上调用BeginInit
和BeginEdit
,最后通过数据网格上的回调,建立单元格绑定:
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
来自影响范围之外的组件,或者您需要在现有代码中添加功能而您又担心破坏事物时,这会非常有用(我从不会这样做)因为我是骑士编码员,他们无情地带着收藏品。)
答案 1 :(得分:1)
答案 2 :(得分:1)
在.NET 4中,现在有一个由ListCollectionView
实现的新接口IEditableCollectionViewAddNewItem
,它拥有一个新方法AddNewItem(object)
。您可以使用它来代替AddNew()
来控制新添加的项目。