かずきのBlog@hatena

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

MVVM開発ってやっぱりExpression Blend無いとめんどくさいと思うようになってきた・・・

Expression Blend触ってて気づいた機能がありました、BehaviorのところにあるCallMethodActionの設定とかドラッグアンドドロップだけで出来るんですね・・・。あとは、ViewModelのDataContextの設定とか、その他もろもろがGUIでサクサクっと出来ちゃう。これはたまりませんな〜。ということで今日見つけた機能です。

ViewとViewModelの関連付け

とりあえずSilverlight(WPFでも可)アプリケーションを作ってPrismを参照に追加に追加して、こんなViewModelをさくっと作成します。特に難しいところはないです。メソッド1つとプロパティ1つあるだけの何の変哲もないクラスです。

namespace MVVMSilverlight.ViewModels
{
    using System;
    using Microsoft.Practices.Prism.ViewModel;

    public class MainPageViewModel : NotificationObject
    {
        private string message;

        public string Message
        {
            get
            {
                return this.message;
            }

            set
            {
                this.message = value;
                this.RaisePropertyChanged(() => Message);
            }
        }

        public void Greet()
        {
            this.Message = "こんにちは! " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
        }
    }
}

ViewとViewModelの関連付け

ここからは、Expression Blendに作業環境をうつします。ViewModelとViewの関連付けからやります。まず、データウィンドウのデータソースの作成からオブジェクトデータソースの作成を選びます。

そして、データソース名とデータソースのクラスを選択してOKを押します。ここではデータソース名をviewModelとして、クラスを先ほど作ったMainPageViewModelにしています。

そうすると、データウィンドウにviewModelという名前で以下のような感じに表示されます。

XAML的には、どうなっているかというとUserControlのResourcesにMainPageViewModelが登録されている感じです。

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:MVVMSilverlight_ViewModels="clr-namespace:MVVMSilverlight.ViewModels" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" x:Class="MVVMSilverlight.MainPage"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
	<UserControl.Resources>
		<MVVMSilverlight_ViewModels:MainPageViewModel x:Key="viewModel" d:IsDataSource="True"/>
	</UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White"/>
</UserControl>

そして、これをLayoutRootのGridのDataContextに設定してやります。これはデータウィンドウからGridにドラッグアンドドロップで関連付け出来ます。MainPageViewModelをつまんで画面にぽとっとやるだけです。親切にDataContextに設定してあげるというガイドまで出てきます。

ドロップすると、Gridを選択した状態でデータウィンドウが以下のような表示になります。DataContextが何に割り当てられているのか一目瞭然ですね。

Bindingもドラッグアンドドロップ

次にデータのバインドをやってみます。TextBlockを画面に1つ置きます。そして、TextBlockにMessageプロパティをドラッグアンドドロップします。そうするとバインドしてやるぜ!ってガイドが出てくるのでぽとっと落とします。

XAML的には以下のような感じになります。ちゃんとバインドされてますね。

<TextBlock HorizontalAlignment="Left" Margin="32,24,0,0" TextWrapping="Wrap" Text="{Binding Message}" VerticalAlignment="Top"/>

CallMethodActionもドラッグアンドドロップ

次にボタンを画面に置いてGreetメソッドをボタンにドラッグアンドドロップすると・・・。

トリガーされたらメソッドを呼び出すだと・・・!?以下のようなXAMLが作成されます。

<Button Content="Button" HorizontalAlignment="Left" Margin="53,48,0,0" VerticalAlignment="Top" Width="75">
    <i:Interaction.Triggers>
    	<i:EventTrigger EventName="Click">
    		<ei:CallMethodAction MethodName="Greet" TargetObject="{Binding}"/>
    	</i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

なんてこった。今までボタンにアセットからCallMethodActionをドラッグアンドドロップして個別にプロパティを設定してたよorz

もちろんCommandもドラッグアンドドロップ

さっきのはViewModelのメソッドを直接ボタンに割り当ててましたが、以下のようにViewModelにCommandを定義するようにして

namespace MVVMSilverlight.ViewModels
{
    using System;
    using Microsoft.Practices.Prism.ViewModel;
using Microsoft.Practices.Prism.Commands;

    public class MainPageViewModel : NotificationObject
    {
        private string message;

        private DelegateCommand greetCommand;

        public string Message
        {
            get
            {
                return this.message;
            }

            set
            {
                this.message = value;
                this.RaisePropertyChanged(() => Message);
            }
        }

        public DelegateCommand GreetCommand
        {
            get
            {
                return this.greetCommand = this.greetCommand ??
                    new DelegateCommand(this.Greet);
            }
        }

        private void Greet()
        {
            this.Message = "こんにちは! " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
        }
    }
}

Blendの画面でGreetCommandをボタンにドラッグアンドドロップすると、素敵にバインドしてくれます。

XAMLは以下のような感じになってました。ばっちりですね。

<Button Content="Button" HorizontalAlignment="Left" Margin="53,48,0,0" VerticalAlignment="Top" Width="75" Command="{Binding GreetCommand, Mode=OneWay}"/>

感想

Visual StudioXAMLを手書きするのとは大きく違う・・・。やっぱお仕事で高い生産性を求められてる場合にはBlend必須なのかな〜と思った今日この頃でした。