問題:
「私はDataGridのオブジェクトを作成する方法を知っている工場を登録する方法を探しています」 。 (ビジネスオブジェクトの私のコレクションは、デフォルトコンストラクタを提供していませんので。)
症状:
我々はDataGrid.CanUserAddRows = true
を設定し、項目はデフォルトを持っていないデータグリッドにアイテムのコレクションをバインドする場合DataGridに '新しい項目行'は表示されません。拘束されているコレクションがBindingList<T>
とき
BindingListCollectionView:
原因:アイテムのコレクションは、任意のWPF ItemControlにバインドされている場合
、WPFは、いずれかでコレクションをラップします。 BindingListCollectionView
はIEditableCollectionViewを実装しますが、IEditableCollectionViewAddNewItem
は実装していません。
a ListCollectionViewバインドされているコレクションが他のコレクションである場合。 ListCollectionView
はIEditableCollectionViewAddNewItem(したがってIEditableCollectionView
)を実装します。
オプション2)の場合、DataGridは新しいアイテムの作成をListCollectionView
に委任します。 ListCollectionView
は内部的にデフォルトコンストラクタの存在をテストし、存在しない場合はAddNew
を無効にします。以下は、DotPeekを使用したListCollectionViewの関連コードです。
public bool CanAddNewItem (method from IEditableCollectionView)
{
get
{
if (!this.IsEditingItem)
return !this.SourceList.IsFixedSize;
else
return false;
}
}
bool CanConstructItem
{
private get
{
if (!this._isItemConstructorValid)
this.EnsureItemConstructor();
return this._itemConstructor != (ConstructorInfo) null;
}
}
この動作を簡単に無効にする方法はないようです。
オプション1の場合、状況はかなり良いです。 DataGridは新しいアイテムの作成をBindingListViewに委譲し、BindingListViewはBindingListに委譲します。 BindingList<T>
はデフォルトコンストラクタの存在もチェックしますが、幸いにもBindingList<T>
では、クライアントがAllowNewプロパティを設定し、新しいアイテムを提供するためのイベントハンドラをアタッチすることもできます。ソリューション後で参照してくださいが、ここではBindingList<T>
public bool AllowNew
{
get
{
if (this.userSetAllowNew || this.allowNew)
return this.allowNew;
else
return this.AddingNewHandled;
}
set
{
bool allowNew = this.AllowNew;
this.userSetAllowNew = true;
this.allowNew = value;
if (allowNew == value)
return;
this.FireListChanged(ListChangedType.Reset, -1);
}
}
非ソリューション内の関連するコードは次のとおりです。データグリッドによって
それは予想するのが妥当だろうDataGridを使用して、クライアントが上記のBindingList<T>
のようにデフォルトの新しい項目を要求するコールバックをアタッチすることができます。これにより、クライアントが必要なときに新しいアイテムを作成する際の最初の亀裂が生じます。
残念ながら、これは.NET 4.5でもDataGridから直接サポートされていません。
.NET 4.5には以前は利用できなかった新しいイベント「AddingNewItem」が表示されますが、これにより新しい項目が追加されていることがわかります。
回避策:同じアセンブリ内のツールによって作成された
- ビジネス・オブジェクト:このシナリオは非常に考えにくい
部分クラスを使用しますが、Entity Frameworkのは、そのエンティティクラスを作成したことを想像デフォルトのコンストラクタを持たない(おそらくシリアル化できない可能性は低い)ので、単にデフォルトのコンストラクタを使って部分クラスを作成することができます。問題が解決しました。
- ビジネスオブジェクトは別のアセンブリにあり、シールされていません。ビジネスオブジェクトのスーパータイプを作成します。
ここでは、ビジネスオブジェクトタイプから継承し、デフォルトのコンストラクタを追加できます。
最初は良いアイデアのようでしたが、2番目の考えでは、ビジネスレイヤーで生成されたデータをビジネスオブジェクトのスーパータイプバージョンにコピーする必要があるため、これ以上の作業が必要になることがあります。
我々は
class MyBusinessObject : BusinessObject
{
public MyBusinessObject(BusinessObject bo){ ... copy properties of bo }
public MyBusinessObject(){}
}
のようなコードが必要になります。そして、いくつかのLINQは、これらのオブジェクトのリスト間で投影します。
- ビジネスオブジェクトは別のアセンブリ内にあり、シールされているかどうかに関係なく、ビジネスオブジェクトをカプセル化します。
このは、今、私たちが行う必要があるすべては、これらのオブジェクトのリスト間に突出するようにいくつかのLINQを使用して、データグリッドでMyBusinessObject.BusinessObject
に結合している
class MyBusinessObject
{
public BusinessObject{ get; private set; }
public MyBusinessObject(BusinessObject bo){ BusinessObject = bo; }
public MyBusinessObject(){}
}
はるかに簡単です。プロパティの不規則な折り返しや値のコピーは必要ありません。
ソリューション:我々はいくつかと、BindingList<BusinessObject>
でビジネスオブジェクトのコレクションをラップして、これにデータグリッドをバインドする場合に使用BindingList<T>
あなたの素晴らしい答えをありがとう。 ListCollectionViewクラスは、IEditableCollectionViewAddNewItemインターフェイスを実装します。 Reflectorを使って実装を見ました。マイクロソフトはこのクラスで多くのパフォーマンスの最適化を行いました。私は、ファクトリメソッドを使うために、このインターフェースを自分で実装したくありません。 – jbe
@jbe。私は理解しています:)また、IEditableCollectionViewAddNewItemに関する情報がたくさんありませんでした。あなたの仕事を達成する方法を見つけたら、更新してください。 –