かずきのBlog@hatena

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

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必須なのかな〜と思った今日この頃でした。