かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

T4 TemplateでViewModelを作る

ちょいと作ってみた。
これをひな形にやっていけばいかなぁ。もっといい方法とかあるよ!って人は教えてください。

ClassDef.ttinclude

とりあえずクラスのメタデータを定義するためのクラス群

<#+ 
// 名前空間
class NSDef
{
	public string NS { get; set; }
	public ClassDef[] Classes { get; set; }
}

// クラスの定義
class ClassDef
{
	public string Name { get; set; }
	public PropertyDef[] Properties { get; set; }
}

// プロパティの定義
class PropertyDef
{
	public string Type { get; set; }
	public string Name { get; set; }
	public string[] Attributes { get; set; }
}
#>
ClassGen.ttinclude

NSDefやClassDefやPropertyDefをもとにしてViewModelのクラスを生成する部分。

<#
foreach (var n in ns)
{
#>
namespace <#= n.NS #>
{
	using System;
	using System.ComponentModel.DataAnnotations;
<#
	foreach (var clazz in n.Classes)
	{
#>
	public partial class <#= clazz.Name #> : WpfApplication15.ViewModelBase
	{
<#
		foreach (var p in clazz.Properties)
		{
#>
		private <#= p.Type #> _<#= p.Name #>;
<#
			foreach (var attr in p.Attributes)
			{
#>
		[<#= attr #>]
<#
			}
#>
		public <#= p.Type #> <#= p.Name #>
		{
			get
			{
				return _<#= p.Name #>; 
			}
			
			set
			{
				if (Equals(value, _<#= p.Name #>))
				{
					return;
				}
                Validator.ValidateProperty(
					value,
					new ValidationContext(this, null, null)
					{
						MemberName = "<#= p.Name #>"
					});
			
				_<#= p.Name #> = value;
				base.OnPropertyChanged("<#= p.Name #>");
			}
		}
<#
		}
#>
	}
<#
	}
#>
}
<#
}
#>
MyClasses.ttinclude

ClassDefとかを使ってクラスのメタデータを定義する。

<#
var ns = new[]
{
	new NSDef
	{
		NS = "WpfApplication15.ViewModels",
		Classes = new[]
		{
			new ClassDef
			{
				Name = "PersonViewModel",
				Properties = new[]
				{
					new PropertyDef
					{
						Type = "string",
						Name = "Name",
						Attributes = new[]
						{
							"Required(ErrorMessage=\"だめよ\")"
						}
					}
				}
			}
		}
	}
};
#>
Generator.tt

上のファイルをとりまとめて実際に自動生成するファイル。

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<#@ include file="ClassDef.ttinclude" #>
// <autogenerated />
<#@ include file="MyClasses.ttinclude" #>
<#@ include file="ClassGen.ttinclude" #>
実際に生成されるコード

こんな感じのコードが作られます。

// <autogenerated />
namespace WpfApplication15.ViewModels
{
	using System;
	using System.ComponentModel.DataAnnotations;
	public partial class PersonViewModel : WpfApplication15.ViewModelBase
	{
		private string _Name;
		[Required(ErrorMessage="だめよ")]
		public string Name
		{
			get
			{
				return _Name; 
			}
			
			set
			{
				if (Equals(value, _Name))
				{
					return;
				}
                Validator.ValidateProperty(
					value,
					new ValidationContext(this, null, null)
					{
						MemberName = "Name"
					});
			
				_Name = value;
				base.OnPropertyChanged("Name");
			}
		}
	}
}
ファイルの配置

こんな感じでプロジェクトに配置してます。

プロジェクトのダウンロードは下から出来ます。
T4VMGen.zip