Livet の Messenger クラスを使ってみる

本日のエントリーでは、Livet の Messenger 機能をチュートリアル風に公開してみます。これを使うと、画面の終了・最大化・最小化・標準化を、コードビハインドを全く書かずに操作することができます。今回は Visual Studio と Blend を使っています。Livet のスニペットの使い方や Blend のビヘイビアの設定方法も合わせて公開してますので、何かのお役にたてば幸いです。



ViewModel にコマンドを定義する

まず Livet のプロジェクトを作成します。今回は*1 あえて VB でプロジェクトを作ってみます。当ブログは、VBユーザーに優しい仕様が自慢です(笑)


プロジェクトが生成されたら、まずは ViewModel にコマンドを作成します。Livet ではコマンドを作るのにスニペットを使うのが定番です。今回作るコマンドは CanExecute 無しの ViewModelCommand を定義します。CanExecute は不要なので、エディタに「lvcomn」と打ち込んで・・・


タブキーを押すとコマンドのスニペットが展開されます。


黄色で強調表示されたコマンドのプレフィックス箇所を「Close」に変更します。


カーソルを移動すると、自動的に強調表示部分がすべて「Close」に置き換わります。


CloseCommand の本体である Close メソッドを実装しましょう。以下のようにコーディングしてください。クラスとメソッドの仕様はここではいちいち解説しません。名前から察してねw

Messenger.Raise(New WindowActionMessage("Close", WindowAction.Close))


するとこうなる。この時点でいったんビルドしてからプロジェクトを保存してください。



Blend でビヘイビアーとコマンドを作成する。

次は Blend を起動して、先ほどのプロジェクトを開きます。MainWindow を開いて「オブジェクトとタイムライン」で Window を選択してください。次に「アセット」から「ビヘイビアー」→「Livet」→「メッセージング」と展開。「WindowInteractionMessageAction」を選択し、「オブジェクトとタイムライン」で選択した Window にドラッグします。


するとこうなる・・・


そしたら、「オブジェクトとタイムライン」で「WindowInteractionMessageAction」を選択し、「プロパティ」→「トリガー」の「新規作成」ボタンをクリックします。


「オブジェクトの選択」で「InteractionMessageTrigger」を選択し、「OK」ボタンをクリックしてください。


「MessageKey」は「Close」と入力します。


「Messenger」は「詳細オプション」から「データバインド」を使って設定します。「詳細オプション」をクリックして、「データバインド」を選択してください。


「データバインドの作成」ウィンドウが表示されたら「データコンテキスト」タブの「フィールド」から、「MainWindowViewModel」→「Messenger」を選択して「OK」を選択してください。


「Messenger」が ViewModel とバインドされて、黄色い枠が表示されました。


次は Window に Button を配置します。


ボタンを選択して、「プロパティ」→「その他」→「Command」の「詳細オプション」をクリック。「データバインド」を選択し、以下の図のように「CloseCommand」を選択して「OK」ボタンをクリックしてください。


これで、ViewModel のコマンドと Button のコマンドがバインドされました。ここまでの XAML です。実行してボタンをクリックすると画面が閉じるか確かめてください。

<Window x:Class="MainWindow"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
	xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
	xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
	xmlns:local="clr-namespace:MessengerSample"
	Title="MainWindow" Height="350" Width="525">
	<i:Interaction.Triggers>
		<l:InteractionMessageTrigger MessageKey="Close" 
			Messenger="{Binding Messenger, Mode=OneWay}">
			<l:WindowInteractionMessageAction/>
		</l:InteractionMessageTrigger>
	</i:Interaction.Triggers>
	<Window.DataContext>
		<local:MainWindowViewModel />
	</Window.DataContext>
	<Grid>
		<Button Content="閉じる" HorizontalAlignment="Left" 
			Height="31" Margin="30,0,0,22" VerticalAlignment="Bottom" 
			Width="75" Command="{Binding CloseCommand, Mode=OneWay}"/>
	</Grid>
</Window>

さらにコマンドを増やしてみる。

同様の手順で、さらに「最大化」「最小化」「標準」ボタンを増やしてみましょう。以下はスニペットを使ってコマンドを増やしたコードです。「MaximizeCommand」「MinimizeCommand」「NormalCommand」の三つのコマンドを追加してますが、Livet のスニペット機能を使えば簡単にコマンドが追加できます。

Public Class MainWindowViewModel
	Inherits ViewModel

#Region "CloseCommand"
	Private _CloseCommand As ViewModelCommand

	Public ReadOnly Property CloseCommand() As ViewModelCommand
		Get
			If _CloseCommand Is Nothing Then
				_CloseCommand = New ViewModelCommand(AddressOf Close)
			End If
			Return _CloseCommand
		End Get
	End Property

	Private Sub Close()
		Messenger.Raise(New WindowActionMessage("Close", WindowAction.Close))
	End Sub
#End Region

#Region "MaximizeCommand"
	Private _MaximizeCommand As ViewModelCommand

	Public ReadOnly Property MaximizeCommand() As ViewModelCommand
		Get
			If _MaximizeCommand Is Nothing Then
				_MaximizeCommand = New ViewModelCommand(AddressOf Maximize)
			End If
			Return _MaximizeCommand
		End Get
	End Property

	Private Sub Maximize()
		Messenger.Raise(New WindowActionMessage("Maximize", WindowAction.Maximize))
	End Sub
#End Region

#Region "MinimizeCommand"
	Private _MinimizeCommand As ViewModelCommand

	Public ReadOnly Property MinimizeCommand() As ViewModelCommand
		Get
			If _MinimizeCommand Is Nothing Then
				_MinimizeCommand = New ViewModelCommand(AddressOf Minimize)
			End If
			Return _MinimizeCommand
		End Get
	End Property

	Private Sub Minimize()
		Messenger.Raise(New WindowActionMessage("Minimize", WindowAction.Minimize))
	End Sub
#End Region

#Region "NormalCommand"
	Private _NormalCommand As ViewModelCommand

	Public ReadOnly Property NormalCommand() As ViewModelCommand
		Get
			If _NormalCommand Is Nothing Then
				_NormalCommand = New ViewModelCommand(AddressOf Normal)
			End If
			Return _NormalCommand
		End Get
	End Property

	Private Sub Normal()
		Messenger.Raise(New WindowActionMessage("Normal", WindowAction.Normal))
	End Sub
#End Region

End Class


Window にさらに三つボタンを追加します。


各ボタンに ViewModel のコマンドをバインドします。あと、InteractionMessageTrigger の追加は XAML をコピペして編集した方が早いです。


完成した Window の XAML です。コードビハインドなしでここまでできるのは便利です。起動して各ボタンをクリックし、動作を確認してみてください。

<Window x:Class="MainWindow"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
	xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
	xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
	xmlns:local="clr-namespace:MessengerSample"
	Title="MainWindow" Height="350" Width="525">
	<i:Interaction.Triggers>
		<l:InteractionMessageTrigger MessageKey="Close" 
			Messenger="{Binding Messenger, Mode=OneWay}">
			<l:WindowInteractionMessageAction/>
		</l:InteractionMessageTrigger>
		<l:InteractionMessageTrigger MessageKey="Maximize" 
			Messenger="{Binding Messenger, Mode=OneWay}">
			<l:WindowInteractionMessageAction/>
		</l:InteractionMessageTrigger>
		<l:InteractionMessageTrigger MessageKey="Minimize" 
			Messenger="{Binding Messenger, Mode=OneWay}">
			<l:WindowInteractionMessageAction/>
		</l:InteractionMessageTrigger>
		<l:InteractionMessageTrigger MessageKey="Normal" 
			Messenger="{Binding Messenger, Mode=OneWay}">
			<l:WindowInteractionMessageAction/>
		</l:InteractionMessageTrigger>
	</i:Interaction.Triggers>
	
	<Window.DataContext>
		<local:MainWindowViewModel />
	</Window.DataContext>
	
	<Grid>
		<Button Content="閉じる" HorizontalAlignment="Left" 
			Height="31" Margin="30,0,0,22" VerticalAlignment="Bottom" 
			Width="75" Command="{Binding CloseCommand, Mode=OneWay}"/>
		<Button Content="最大化" HorizontalAlignment="Left" 
			Height="31" Margin="130,0,0,22" VerticalAlignment="Bottom" 
			Width="75" Command="{Binding MaximizeCommand, Mode=OneWay}"/>
		<Button Content="最小化" HorizontalAlignment="Left" 
			Height="31" Margin="230,0,0,22" VerticalAlignment="Bottom" 
			Width="75" Command="{Binding MinimizeCommand, Mode=OneWay}" />
		<Button Content="標準" HorizontalAlignment="Left" 
			Height="31" Margin="330,0,0,22" VerticalAlignment="Bottom" 
			Width="75" Command="{Binding NormalCommand, Mode=OneWay}"/>
	</Grid>
</Window>


 

*1:今回もw