WPFでEF(Entitiy Framework)を使っていると、リスト表示には楽なのだが、データを反映するためにはINotifyPropertyChangedを継承させなくてはいけなくて、そこが面倒くさい。いちいち、ViewModel クラスで EF のクラスをくるめば良いのだが、それを自動化したい。
特にマスター管理用の画面なんかを作るときは、ASP.NET MVCのように足場を自動化させておきたいというのもある。
EFで出力されるクラスは、下記のようなクラスなので、
public partial class 社員名
{
public int 社員ID { get; set; }
public Nullable<int> 部署ID { get; set; }
public Nullable<int> 営業担当FLG { get; set; }
public string 社員名1 { get; set; }
}
MVVM対応のINotifyPropertyChangedインターフェースを継承したこんなクラスにしたいわけだ。
public partial class 社員名 : ObservableObject
{
private int _社員ID ;
public int 社員ID {
get { return _社員ID; }
set { SetProperty( ref _社員ID, value, nameof(社員ID)); }
}
private Nullable<int> _部署ID ;
public Nullable<int> 部署ID {
get { return _部署ID; }
set { SetProperty( ref _部署ID, value, nameof(部署ID)); }
}
private Nullable<int> _営業担当FLG ;
public Nullable<int> 営業担当FLG {
get { return _営業担当FLG; }
set { SetProperty( ref _営業担当FLG, value, nameof(営業担当FLG)); }
}
private string _社員名1 ;
public string 社員名1 {
get { return _社員名1; }
set { SetProperty( ref _社員名1, value, nameof(社員名1)); }
}
}
こうしておくと、リストビューで一覧表示をさせておいて、選択時にテキストボックスへ表示、そしてテキストボックスでの変更がリストビューに反映される、というところが自動化される。
Model1.ttを直接書き替える
元のクラスにスクリプトを通して、MVVM対応のクラスを作ろうかとも思ったのだが、もっと簡単に EF で出力される Model1.tt を直接書き替えてしまう。T4 で書かれている Model1.tt はファイルに保存した途端にテンプレートに従って各クラスが出力される。
public class CodeStringGenerator
{
...
public string Property(EdmProperty edmProperty)
{
return string.Format(
CultureInfo.InvariantCulture,
// ★ここを書き替え
@"private {1} _{2} ;
{0} {1} {2} {{
get {{ return _{2}; }}
set {{ SetProperty( ref _{2}, value, nameof({2})); }}
}}",
// "{0} {1} {2} {{ {3}get; {4}set; }}",
Accessibility.ForProperty(edmProperty),
_typeMapper.GetTypeName(edmProperty.TypeUsage),
_code.Escape(edmProperty),
_code.SpaceAfter(Accessibility.ForGetter(edmProperty)),
_code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
}
...
public string EntityClassOpening(EntityType entity)
{
return string.Format(
CultureInfo.InvariantCulture,
// ★ここを書き替え
"{0} {1}partial class {2}{3} : ObservableObject ",
Accessibility.ForType(entity),
_code.SpaceAfter(_code.AbstractOption(entity)),
_code.Escape(entity),
_code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType)));
}
...
}
大ざっぱだが、CodeStringGeneratorクラスのPropertyメソッドとEntityClassOpeningメソッドの内容を書き替えてしまう。
EntityClassOpening は、エンティティのクラスを出力するところなので、INotifyPropertyChangedインターフェースを実装した「ObservableObject」クラスを継承するように書き替える。ObservableObjectクラスは別途自前で用意しておく。
Property メソッドは、プロパティを出力するところなので、SetProperty メソッドを呼び出して変更通知が飛ぶようにする。
これを保存すると、各エンティティのクラスが、
public partial class 社員名 : ObservableObject
{
private int _社員ID ;
public int 社員ID {
get { return _社員ID; }
set { SetProperty( ref _社員ID, value, nameof(社員ID)); }
}
...
}
のように書き変わる。
のような画面が、バインドだけで作れるようになる。

