かずきのBlog@hatena

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

Blendのクラスのサンプルデータをプログラムで機械的に作りたい

Blend for VS2013からWindows ストア アプリでもサンプルデータがサポートされるようになりました。これでWPF, Silverlight(何で切られてしまったん…), Windows Phone(何で日本で出ないの…), Windows ストア アプリで同じようにデザイナ画面でデータを見ながら画面のデザインが出来るようになります。

ViewModelを定義している場合は、クラスを元にしたサンプルデータを作ると思うのですが、このデータがなんとXAMLで書かれています。例えば、以下のようなクラスがあるとします。

using System.Collections.ObjectModel;

namespace SampleDataGenApp
{
    public class ApplicationModel
    {
        public ObservableCollection<Person> People { get; set; }
    }

    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }
}

このクラスを元にBlendでサンプルデータを作ります。

f:id:okazuki:20131026230517p:plain

そうすると、プロジェクトの下にSampleDataというフォルダが作られ、ApplicationModelSampleData.xamlというXAMLが作られます。このXAMLの中は以下のようになっています。

<SampleDataGenApp:ApplicationModel xmlns:SampleDataGenApp="using:SampleDataGenApp">
    <SampleDataGenApp:ApplicationModel.People>
        <SampleDataGenApp:Person Age="22" Id="24" Name="Cras class"/>
        <SampleDataGenApp:Person Age="83" Id="62" Name="Aenean maecenas curabitur"/>
        <SampleDataGenApp:Person Age="23" Id="96" Name="Praesent duis nam"/>
        <SampleDataGenApp:Person Age="16" Id="43" Name="Vestibulum mauris nunc amet"/>
        <SampleDataGenApp:Person Age="93" Id="54" Name="Phasellus ante adipiscing curae aliquam"/>
        <SampleDataGenApp:Person Age="11" Id="37" Name="Integer parturient nullam donec"/>
        <SampleDataGenApp:Person Age="17" Id="20" Name="Sed arcu"/>
        <SampleDataGenApp:Person Age="86" Id="25" Name="Consequat vestibulum"/>
        <SampleDataGenApp:Person Age="20" Id="92" Name="Vestibulum accumsan diam quisque dis"/>
        <SampleDataGenApp:Person Age="91" Id="87" Name="Aptent vivamus est"/>
    </SampleDataGenApp:ApplicationModel.People>
</SampleDataGenApp:ApplicationModel>

とても文字列とか英語チックです。メールアドレスや、URLなんかをサンプルデータに使うようにすると、それっぽくなりますが、それ以外の文字列はとても英語です。はい。

そして、このサンプルデータをいじろうとしたとしても、Personクラスは100件くらい機械的なデータがとりあえずあればいいや!みたいな状態でも、XAMLをちまちまコピペしないといけません。これは怠い。

そうだT4を使おう

未だにVisual Studioの標準機能でシンタックスハイライトすらされてないT4テンプレートですが、こいつを使うと、このサンプルデータをいい具合にできます。まず、サンプルデータのXAMLと同じ名前の.ttファイルを作成します。

f:id:okazuki:20131026230957p:plain

そして、オリジナルのAppliationModelSampleData.xamlの中身をコピーして.ttのファイルに貼り付けます。

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".txt" #>

<SampleDataGenApp:ApplicationModel xmlns:SampleDataGenApp="using:SampleDataGenApp">
    <SampleDataGenApp:ApplicationModel.People>
        <SampleDataGenApp:Person Age="22" Id="24" Name="Cras class"/>
        <SampleDataGenApp:Person Age="83" Id="62" Name="Aenean maecenas curabitur"/>
        <SampleDataGenApp:Person Age="23" Id="96" Name="Praesent duis nam"/>
        <SampleDataGenApp:Person Age="16" Id="43" Name="Vestibulum mauris nunc amet"/>
        <SampleDataGenApp:Person Age="93" Id="54" Name="Phasellus ante adipiscing curae aliquam"/>
        <SampleDataGenApp:Person Age="11" Id="37" Name="Integer parturient nullam donec"/>
        <SampleDataGenApp:Person Age="17" Id="20" Name="Sed arcu"/>
        <SampleDataGenApp:Person Age="86" Id="25" Name="Consequat vestibulum"/>
        <SampleDataGenApp:Person Age="20" Id="92" Name="Vestibulum accumsan diam quisque dis"/>
        <SampleDataGenApp:Person Age="91" Id="87" Name="Aptent vivamus est"/>
    </SampleDataGenApp:ApplicationModel.People>
</SampleDataGenApp:ApplicationModel>

そして、ApplicationModelSampleData.xamlを削除します。最後に、.ttファイルの中の<#@ output extesion=".txt" #>となっている箇所を<#@ output extesion=".xaml" #>に変更します。

これで、ソリューションエクスプローラは以下のようになります。

f:id:okazuki:20131026231305p:plain

.ttファイルから生成された.xamlファイルを選択してプロパティのビルドアクションをPageからDesignDataに変更します。

f:id:okazuki:20131026231426p:plain

ビルドして、Visual StudioからBlendに戻ってエラーが無ければ成功です。

データを作ろう

今は固定のデータをT4テンプレートに貼り付けただけなので、以下のようにテンプレートを書き換えてサンプルデータを適当に100件作ってみました。

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".xaml" #>

<#
var r = new Random();
#>

<SampleDataGenApp:ApplicationModel xmlns:SampleDataGenApp="using:SampleDataGenApp">
    <SampleDataGenApp:ApplicationModel.People>
    <#
    foreach (var i in Enumerable.Range(0, 100))
    {
    #>
        <SampleDataGenApp:Person Age="<#= r.Next(100) #>" Id="<#= i #>" Name="サンプル 太郎<#= i #>"/>
    <#
    }
    #>
    </SampleDataGenApp:ApplicationModel.People>
</SampleDataGenApp:ApplicationModel>

生成されるXAMLは長いので省略します。BlendでサンプルデータのApplicationModelのPeopleを画面にドロップしてみると、ちゃんとT4テンプレートで生成されたサンプルデータが使われていることが確認できます。

f:id:okazuki:20131026231950p:plain

まとめ

サンプルデータを生成するのにT4テンプレートを活用してもよさそうな雰囲気を感じました。どうでしょう。