Tom*_*ila 5 wpf listcollectionview
如何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;
}
}
Run Code Online (Sandbox Code Playgroud)
陈旧的问题值得新的答案:)
派生类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);
}
}
Run Code Online (Sandbox Code Playgroud)
这很有效,因为除了具有几乎相同的实现之外,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);
}
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
在这里,我将源代码包含到我的 中,当我不知道设计时需要什么类型时,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);
}
}
Run Code Online (Sandbox Code Playgroud)
我喜欢这种方法,因为它为AddNew可能需要在运行时将 的类型从一种类型调整为另一种类型的情况提供了最大的灵活性。它还允许AddNew添加集合中的第一项,当列表源最初为空但可以确定其基础类型时,这很方便。
此链接讨论了强制使用类型的替代方法AddNew()。_itemConstructor它使用反射将所使用的私有属性设置AddNew为指定类型的无参数构造函数。当您ListCollectionView来自不受您影响的组件时,或者您需要向现有代码中添加功能并且您担心破坏东西时(我从来不会这样做,因为我是一个无情的编码器,这会特别有用)与集合)。