記事のカテゴリー: C#、.NET 9、WPF
自作の添付プロパティを使用するとき、XAMLで指定するBindingModeによって変わる挙動についてまとめてみました。
サンプル
例として、TextBoxのSelectedTextプロパティ(選択範囲の文字を取得、設定するプロパティ)にバインドできるようにする添付ビヘイビアを用意します。OnBindableSelectedTextChangedメソッドでBindingModeを判断して必要な処理だけをする、という内容になっています。実際に動かしてみると、BindingModeがOneWayToSourceの場合は思った通りに動いてくれません。
C#:
public static class TextBoxExtensions { private static List<TextBox> attachingTargets = []; // TextBox の SelectedText プロパティにバインドできるようにする添付プロパティ public static readonly DependencyProperty BindableSelectedTextProperty = DependencyProperty.RegisterAttached( "BindableSelectedText", typeof(string), typeof(TextBoxExtensions), new PropertyMetadata(string.Empty, OnBindableSelectedTextChanged)); public static string GetBindableSelectedText(DependencyObject obj) { return (string)obj.GetValue(BindableSelectedTextProperty); } public static void SetBindableSelectedText(DependencyObject obj, string value) { obj.SetValue(BindableSelectedTextProperty, value); } // 添付プロパティの値が変わったときに呼ばれる処理 private static void OnBindableSelectedTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not TextBox textBox) { return; } BindingMode mode = BindingOperations.GetBinding(d, BindableSelectedTextProperty).Mode; // BindingMode が TwoWay か OneWayToSource の場合は TextBox の変更を監視する if ((mode == BindingMode.TwoWay) || (mode == BindingMode.OneWayToSource)) { if (!attachingTargets.Contains(textBox)) { attachingTargets.Add(textBox); textBox.SelectionChanged += TextBox_SelectionChanged; } } // BindingMode が OneWayToSource でない場合は TextBox に値を反映する if (mode != BindingMode.OneWayToSource) { if ((e.NewValue is string value) && (value != textBox.SelectedText)) { textBox.SelectedText = value; } } } // TextBox の選択範囲のインデックスや文字が変わったときに呼ばれる処理 private static void TextBox_SelectionChanged(object sender, RoutedEventArgs e) { if ((sender is TextBox textBox) && (textBox.SelectedText != GetBindableSelectedText(textBox))) { SetBindableSelectedText(textBox, textBox.SelectedText); } } }
XAML:
<TextBox local:TextBoxExtensions.BindableSelectedText="{Binding SelectedText, Mode=TwoWay}" />
実際の挙動
XAMLで指定するBindingModeによって挙動は次のようになりました。 OneWayToSourceの場合は思った通りの挙動をしません。回避策としては、BindableSelectedText添付プロパティとは別にTextBoxの監視をするための添付プロパティを用意して、そちらからBindableSelectedTextの値を変更する方法があります(参照先にコードがあります)。
- TwoWay: 思った通りの挙動をする
- OnBindableSelectedTextChanged メソッドは呼ばれる
- TextBox_SelectionChanged メソッドは呼ばれる
- OneWay: 思った通りの挙動をする
- OnBindableSelectedTextChanged メソッドは呼ばれる
- TextBox_SelectionChanged メソッドは呼ばれない(未登録なので当然)
- OneTime: 思った通りの挙動をする
- OnBindableSelectedTextChanged メソッドは1回だけ呼ばれる
- TextBox_SelectionChanged メソッドは呼ばれない(未登録なので当然)
- OneWayToSource: 思った通りの挙動をしない
- OnBindableSelectedTextChanged メソッドは呼ばれない
- TextBox_SelectionChanged メソッドは呼ばれない(未登録なので当然)
0 件のコメント:
コメントを投稿