古い質問は新鮮な答えに値します:)
からクラスを派生させること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
です。これは、リストソースが最初は空の場合に便利ですが、基になるタイプを判別できます。
このリンクでは、によって使用されるタイプを強制する別の方法について説明していAddNew()
ます。リフレクションを使用して、_itemConstructor
によって使用されるプライベートプロパティAddNew
を指定されたタイプのパラメーターなしのコンストラクターに設定します。これは、影響力のないコンポーネントから来ている場合、または既存のコードに機能を追加する必要があり、物事を壊すことを心配している場合に特に役立ちますListCollectionView
(私は大酒飲みのコーダーであるため、私は決してそうはなりません)コレクション付き)。