PrismWPFSample(12)Behavior

Prismを使用したWPFアプリケーション開発で役に立つと思われる項目を一つのアプリケーションにまとめたものを作りました。今回は、TextBoxの入力時にENTERでバインドを更新するビヘイビアの追加です。(ESCでキャンセルも追加)

動作環境:Win10, Visual Studio Community 2017, Prism V7.1.0.431, .NET4.5.2, Prism Template Pack, TraceListeners, WPFLocalizeExtension, OxyPlot

f:id:feynman911:20190818222849j:plain

TextBox のバインドタイミング

TextBox のバインドタイミングには、以下のものがあります。
f:id:feynman911:20190812100633j:plain

  • PropertyChanged:内容が変化する毎に更新されます。TextBoxの文字を1文字書き換える都度、更新されるので、あまり好ましくありません。
  • LostFocus:TextBoxからフォーカスが移動した時に更新されます。入力後、他のTextBoxをクリックする等してフォーカスを外さないと更新されないので面倒です。
  • Explicit:自動ではなく明示的に更新してあげる必要があります。

ENTERキーでバインドを更新するビヘイビア

よく見かける 「Enterキーで更新」をしたいので、ビヘイビアで作ることにします。
ESCAPEキーで変更キャンセルも追加しました。

using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Controls;
using System.Windows.Data;

namespace CommonModels.Behaviors
{
    /// <summary>
    /// TextBoxでEnterが押された時にバインドを更新します
    /// </summary>
    [TypeConstraint(typeof(TextBox))]
    public class TextBoxEnterBindBehavior : Behavior<TextBox>
    {
        /// <summary>
        /// 要素にアタッチされた時にイベントハンドラを登録
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.PreviewKeyDown += OnPreviewKeyDown;
        }

        /// <summary>
        /// 要素にデタッチされた時にイベントハンドラを解除
        /// </summary>
        protected override void OnDetaching()
        {
            base.OnDetaching();
            this.AssociatedObject.PreviewKeyDown -= OnPreviewKeyDown;
        }

        /// <summary>
        /// キーダウン時のプレビューでKey.Enterを検出してUpdate
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnPreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                // エンターキーが押されたら BindingをUpdateする
                TextBox tBox = (TextBox)sender;
                DependencyProperty prop = TextBox.TextProperty;
                BindingExpression binding
                 = BindingOperations.GetBindingExpression(tBox, prop);
                if (binding != null) { binding.UpdateSource(); }
            }
            if (e.Key == Key.Escape)
            {
                // エスケープが押されたら 変更をキャンセルする
                TextBox tBox = (TextBox)sender;
                DependencyProperty prop = TextBox.TextProperty;
                BindingExpression binding
                    = BindingOperations.GetBindingExpression(tBox, prop);
                if (binding != null) { binding.UpdateTarget(); }
            }
        }
    }
}

ビヘイビアの適用

コンバーターのサンプルのTextBoxにも使用しました。
Blendで適用したい TextBox に TextBoxEnterBindBehavior をドラッグ&ドロップして使用します。

f:id:feynman911:20190812103406j:plain


作成したサンプルは次の場所に置いてありますので、詳しくはソースコードを見てもらえればと思います。
github.com