#ビヘイビアとは
言葉の意味は「振る舞い」。WPFでMVVMに準拠する際、Viewの状態の変化をきっかけにして、Viewで実行される処理の実装方法のことを指す。MVVMに準拠するとコードビハインドが使えないので、その代替手段ということになる。
#実装方法
##添付プロパティ
添付プロパティの実装に、振る舞いを含めてしまう。
###コールバック
添付プロパティは初期化時にコールバックが登録できる。そこに実行したい処理を記述することで、プロパティの値の変更をきっかけとしたビヘイビアが作れる。
using System.Windows;
namespace Sample {
public class AttachedXXX {
public static DependencyProperty XXXProperty
= DependencyProperty.RegisterAttached(
"XXX",
typeof(bool),
typeof(AttachedXXX),
new PropertyMetadata(XXX_PropertyChanged) //コールバックを登録
);
public static void SetXXX(DependencyObject obj, bool value)
=> obj.SetValue(XXXProperty, value);
public static bool GetXXX(DependencyObject obj)
=> (bool)obj.GetValue(XXXProperty);
//コールバック
private static void XXX_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
if (e.NewValue != null) {
//値の変更に対する振る舞いを記述する
}
}
}
}
<Window x:Class="Sample.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Sample"
Title="MainView" Height="300" Width="300">
<Grid>
<TextBox local:AttachedXXX.XXX="{Binding XXX}" />
</Grid>
</Window>
これだけではできることが限られるため、実際は次項の添付ビヘイビアとして利用されることが多い。
###添付ビヘイビア
コールバック内でViewのイベントハンドラを登録する。この方法は「添付ビヘイビア」と呼ばれており、ビヘイビアの実装方法としてはメジャーだが、Microsoftのサイトには解説がない。
using System.Windows;
namespace Sample {
public class AttachedXXX {
public static DependencyProperty XXXProperty
= DependencyProperty.RegisterAttached(
"XXX",
typeof(bool),
typeof(AttachedXXX),
new PropertyMetadata(XXX_PropertyChanged) //コールバックを登録
);
public static void SetXXX(DependencyObject obj, bool value)
=> obj.SetValue(XXXProperty, value);
public static bool GetXXX(DependencyObject obj)
=> (bool)obj.GetValue(XXXProperty);
//コールバック
private static void XXX_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var textBox = d as TextBox;
if (textBox == null) return;
//イベントハンドラの登録
if (e.NewValue != null) {
textBox.PreviewTextInput += TextBox_PreviewTextInput;
} else {
textBox.PreviewTextInput -= TextBox_PreviewTextInput;
}
}
//イベントハンドラ
private static void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e) {
//振る舞い
}
}
}
コールバックでは、イベントハンドラの登録/解除のみ行う。プロパティと振る舞いが連動しないため、何をしているのかわかりにくいコードになる。
この方法は、ビヘイビアがプロパティを必要としない場合には使えない。一方で、プロパティなのでスタイル指定できるというメリットがある。
##Blend SDK
Blend SDKのSystem.Windows.Interactivity.dllに用意された専用のクラスを使う。
###Behaviorクラス
ビヘイビアを実装するための専用のクラス。このクラスを継承してビヘイビアを実装する。
using System;
using System.Windows.Controls;
using System.Windows.Interactivity;
namespace Sample {
public class YYYBehavior : Behavior<Control> {
protected override void OnAttached() {
base.OnAttached();
AssociatedObject.Loaded += AssociatedObject_Loaded;
}
protected override void OnDetaching() {
base.OnDetaching();
AssociatedObject.Loaded -= AssociatedObject_Loaded;
}
//イベントハンドラ
private void AssociatedObject_Loaded(object sender, RoutedEventArgs e) {
//振る舞い
}
}
}
<Window x:Class="Sample.MainView"
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:local="clr-namespace:Sample"
Title="MainView" Height="300" Width="300">
<Grid>
<Button Content="OK">
<i:Interaction.Behaviors>
<local:YYYBehavior/>
</i:Interaction.Behaviors>
</Button>
</Grid>
</Window>
添付ビヘイビアとは違い、専用のクラスなのでわかりやすいコードになるが、xamlの構造が複雑になるというデメリットがある。また、添付ビヘイビアと違いスタイルでの指定ができない。(工夫すればできるが、xamlがより複雑になる。)
###TriggerBaseクラスとTriggerActionクラス
今までの方法はきっかけと振る舞いを同時に定義しているが、両者を個別に指定する方法が用意されており、きっかけは「トリガー」、振る舞いは「アクション」と呼ばれる。主なトリガーとアクションが最初から用意されており、これらを組み合わせることで、単純なビヘイビアなら簡単に実現できる。
<Window x:Class="Sample.MainView"
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:local="clr-namespace:Sample"
Title="MainView" Height="300" Width="300">
<Grid>
<Label Content="OK">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding XXXCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
</Window>
自作する場合は、TriggerBaseクラスを継承してトリガーを、TriggerActionクラスを継承してアクションを実装する。
PrismのInteractionRequestTriggerを使えばViewModel側からアクションを実行できるので、MVVMを守りながらViewを操作する手段として重宝する。(例:MVVMでファイルダイアログを使用する)