かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

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