WPFの添付ビヘイビア
添付ビヘイビアとは
MVVMモデルを採用したWPFにおいて、Viewの状態変化に伴って実行される処理を定義したい場合に使用されるテクニックです。
MVVMの思想上View、つまりコードビハインドに処理を書くのはご法度ですが、
Viewで完結する処理をViewModelに書くのもあまりいいとは言えません。
そこで、WPFの添付プロパティを自作する処理にまとめてコードビハインドに書きたかった処理を記載することで
Viewのビヘイビア(= 振る舞い)を表現するテクニックになります。
イメージ
サンプルコード
実際に作成してみたビヘイビアがこちら。
using System.Windows;
using System.Windows.Input;
namespace WPF.Views.Behaviors
{
internal class MessageDialogBehavior
{
// 1. DependencyPropertyインスタンスを生成
public static readonly DependencyProperty ShowMessageProperty = DependencyProperty.RegisterAttached(
"ShowMessage",
typeof(bool),
typeof(MessageDialogBehavior),
new PropertyMetadata(false, OnShowMessage)
);
// 2. Getterを作成
public static bool GetShowMessage(DependencyObject target)
=> (bool)target.GetValue(ShowMessageProperty);
// 3. Setterを作成
public static void SetShowMessage(DependencyObject target, bool value)
=> target.SetValue(ShowMessageProperty, value);
// 4. callbackメソッドを定義
private static void OnShowMessage(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var element = sender as UIElement;
if (element == null)
{
return;
}
var newValue = (bool)e.NewValue;
if ((bool)e.NewValue)
{
element.MouseRightButtonDown += ShowMessage;
} else
{
element.MouseRightButtonDown -= ShowMessage;
}
}
private static void ShowMessage(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Behavior Sample.");
}
}
}
添付プロパティで True
を指定したコントロールで右クリックするとポップアップが表示されるものになります。
1. DependencyPropertyインスタンスを生成
まずは DependencyProperty.RegisterAttached()
を利用してDependencyPropertyインスタンスを 生成します。
DependencyProperty.RegisterAttached()
が要求する4つの引数には次の内容を記載します。
引数 | |
---|---|
第1引数 | プロパティ名を string 指定します。この値が実際にXAMLで指定するプロパティ名になります。 |
第2引数 | プロパティの型を Type で指定します。 |
第3引数 | プロパティを所有する型を Type で指定します。今回の場合は自分自身である MessageDialogBehavior になります。 |
第4引数 | メタデータを指定します。 実際の値としては PropertyMetadata のインスタンスになります。 |
PropertyMetadataについて
DependencyProperty
インスタンスの生成に必要な PropertyMetadata
インスタンスですが、
デフォルトコンストラクタの他に4種類のオーバーロードで用意されていて、状況に応じて使い分けることになります。
各コンストラクタの引数は以下の通りです。
// ※一部省略
namespace System.Windows
{
public class PropertyMetadata
{
public PropertyMetadata();
public PropertyMetadata(object defaultValue);
public PropertyMetadata(PropertyChangedCallback propertyChangedCallback);
public PropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback);
public PropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback);
}
}
今回使用したのはこのコンストラクタです。
public PropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback);
添付プロパティのデフォルト値と、値が変更された際のcallbackを指定しています。
※callbackがどのように使用されるかは後述
2. Getterを作成
添付プロパティの値を取得するためのメソッドを定義します。
引数の DependencyObject
の GetValue()
メソッドの戻り値を
「1. DependencyPropertyインスタンスを生成」でRegisterAttached()
の第2引数に指定した
型でキャストして返します。
※第2引数はプロパティの型でした
メソッド名について
Getterのメソッド名は必ず Get + プロパティ名 とする必要があります。
今回の場合だとプロパティ名を ShowMessage
としているので、Geeterのメソッド名は GetShowMessage
となります。
3. Setterを作成
添付プロパティの値を設定するためのメソッドを定義します。
引数の DependencyObject
の SetValue()
メソッドを使用して設定を行います。
メソッド名について
Getterと同じく、Setterのメソッド名も必ず Set + プロパティ名 とする必要があります。
そのため今回の場合だと、メソッド名は SetShowMessage
となります。
4. callbackメソッドを定義
値が変更されたときに実行するcallbackメソッドを定義しています。
これは「1. DependencyPropertyインスタンスを生成」で登場した
PropertyMetadata
コンストラクタの第2引数として使用されています。
この中で少し独特だなと感じたのはこの部分でした。
if ((bool)e.NewValue)
{
element.MouseRightButtonDown += ShowMessage;
} else
{
element.MouseRightButtonDown -= ShowMessage;
}
DependencyPropertyChangedEventArgs
の e
で変更前と変更後の値を取得できるのですが
今回は特に何かしらの処理で値を変更するといった処理は行っていません。
にもかかわらず、変更前・変更後どちらからも値が取得できるようになっていました。
デバッグして確認してみたところ、どうやら値を変更するような処理を行っていなくても
変更前の値である e.OldValue
にはデフォルト値が設定されているようでした。
で、このデフォルト値がどこで指定されているかというと...
public static readonly DependencyProperty ShowMessageProperty = DependencyProperty.RegisterAttached(
"ShowMessage",
typeof(bool),
typeof(MessageDialogBehavior),
new PropertyMetadata(false, OnShowMessage) // ここの第1引数
);
DependencyProperty
インスタンス作成時に指定していました!
初期値がfalseなので実質添付プロパティでTrueを指定するとcallbackメソッドが実行されるとなっています。
View側の記述
このビヘイビアを実際に使用するためのXAMLと使用結果は以下の通りです。
<Window x:Class="WPFP.Views.BehaviorSample"
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:local="clr-namespace:WPFP.Views"
xmlns:b="clr-namespace:WPFP.Views.Behaviors"
mc:Ignorable="d"
Title="BehaviorSample" Height="450" Width="800">
<StackPanel>
<TextBlock Text="Trueにするとメッセージボックスが表示される"
Margin="5"
FontSize="20"
b:MessageDialogBehavior.ShowMessage="True" />
<TextBlock Text="falseだとメッセージボックスが表示されない"
Margin="5"
FontSize="20"
b:MessageDialogBehavior.ShowMessage="False" />
</StackPanel>
</Window>
実行結果はこんな感じ。
Author And Source
この問題について(WPFの添付ビヘイビア), 我々は、より多くの情報をここで見つけました https://qiita.com/ebipilaf/items/fa64eb804e58c98ecdcc著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .