TextBoxフォーカス時における挙動を変えたいと思った。(壱)

TextBoxにフォーカス(キーボードフォーカス)が当たった時、

・入力されている文字列を全選択したい。
 →追加ではなく、上書きというアクションをデフォルトとする。
・一番右にカレット(|で点滅する位置)を配置したい。
 →後に追加していくアクションをデフォルトとする
・一番左にカレット(|で点滅する位置)を配置したい。
 →前に追加していくアクションをデフォルトとする
・任意の位置にカレットを配置する。
 →上記以外の特殊な用途。

と色々XAML上から設定できないものかと考えた。まあ、考えただけで済むはずもなく、作ったんだけど。これも添付プロパティでなんとかなったんだけど。
まずは上記用途を選択するための(添付プロパティの値となる)Enumを定義する。

using System;

namespace TawamureDays {

/// <summary>
/// キーボードフォーカス取得時の振る舞いを示すEnum
/// </summary>
/// <remarks>
/// テキストボックスのフォーカス時の動作を決めるためのEnumです。<br/>
/// </remarks>
public enum BehaviorOnFocus : int {
/// <summary>なし(初期値)</summary>
None = 0,
/// <summary>全選択</summary>
SelectAll,
/// <summary>カレットを左に配置</summary>
CaretLeft,
/// <summary>カレットを右に配置</summary>
CaretRight,
/// <summary>カレットを指定位置に配置(カスタム用)</summary>
CaretOptional
}
}

初期値(None)は、XAML上では設定しない。添付プロパティのデフォルト値となる値。とりあえず、一番下(カスタム)以外を実装する。

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace TawamureDays {

/// <summary>
/// TextBoxコントロール用ビヘイビアクラス
/// </summary>
/// <remarks>
/// TextBoxコントロールに対する添付プロパティ(ビヘイビア)を提供するクラスです。<br/>
/// </remarks>
public static class TextBoxBehavior {

/// <summary>
/// フォーカス取得時の振る舞いを取得します。
/// </summary>
/// <param name="obj">対象オブジェクト(TextBox)</param>
/// <returns>振る舞いを示すEnum</returns>
public static BehaviorOnFocus GetBehavoirOnGotFocus(DependencyObject obj) {
return (BehaviorOnFocus)obj.GetValue(BehavoirOnGotFocusProperty);
}

/// <summary>
/// フォーカス取得時の振る舞いを設定します。
/// </summary>
/// <param name="obj">対象オブジェクト(TextBox)</param>
/// <param name="value">振る舞いを示すEnum</param>
public static void SetBehavoirOnGotFocus(DependencyObject obj, BehaviorOnFocus value) {
obj.SetValue(BehavoirOnGotFocusProperty, value);
}

/// <summary>フォーカス取得時の振る舞い</summary>
public static readonly DependencyProperty BehavoirOnGotFocusProperty =
DependencyProperty.RegisterAttached("BehavoirOnGotFocus", typeof(BehaviorOnFocus),
typeof(TextBoxBehavior),
new UIPropertyMetadata(BehaviorOnFocus.None,
OnBehavoirOnGotFocusPropertyChanged));

/// <summary>
/// BehavoirOnGotFocusProperty変更イベントハンドラ
/// </summary>
/// <param name="dpObj">イベント発生元</param>
/// <param name="e">イベント引数</param>
private static void OnBehavoirOnGotFocusPropertyChanged(
DependencyObject dpObj, DependencyPropertyChangedEventArgs e) {
var txtBox = dpObj as TextBox;

if (txtBox == null) {
//TextBox系以外は受け付けません。
return;
}

txtBox.GotKeyboardFocus -=
new KeyboardFocusChangedEventHandler(TxtBox_GotKeyboardFocus);

if (e.NewValue != null && ((BehaviorOnFocus)e.NewValue) != BehaviorOnFocus.None) {
txtBox.GotKeyboardFocus +=
new KeyboardFocusChangedEventHandler(TxtBox_GotKeyboardFocus);

//※当然ながら、画面終了時にイベントからハンドラを削除する実装が必須です。
}

return;
}

/// <summary>
/// キーボードフォーカスイベントハンドラ
/// </summary>
/// <param name="sender">イベント発生用</param>
/// <param name="e">イベント引数</param>
private static void TxtBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) {
var txtBox = sender as TextBox;

if (txtBox == null || !txtBox.Focusable || !txtBox.IsEnabled ||
txtBox.Visibility != Visibility.Visible) {
//表示中でフォーカス可能で、有効であるときのみ処理可能。
//それ以外は無視です。
return;
}

var behavior = TextBoxBehavior.GetBehavoirOnGotFocus(txtBox);

switch (behavior) {
case BehaviorOnFocus.None:
//何もしない
break;
case BehaviorOnFocus.SelectAll:
//すべて選択
txtBox.SelectAll();
break;
case BehaviorOnFocus.CaretLeft:
//一番左にカレットを移動
txtBox.CaretIndex = 0;
break;
case BehaviorOnFocus.CaretRight:
//一番右にカレットを移動
txtBox.CaretIndex = txtBox.Text.Length;
break;
case BehaviorOnFocus.CaretOptional:
//カスタムを本当は実装する
break;
default:
break;
}
}
}
}

XAML上の設定

<Window x:Class="TawamureDays.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:local="clr-namespace:TawamureDays"
Title="MainWindow" Height="213" Width="385"
local:WindowBehavior.UseMessageCommand="True"
local:FrameworkElementBehavior.OnLoadedCommand="{Binding LoadedCommand}"
>
<Grid>
<i:Interaction.Behaviors>
<local:FocusMoveBehavior Key="Enter"/>
</i:Interaction.Behaviors>
<StackPanel>
<TextBlock Text="フォーカス時、全選択"/>
<TextBox Text="Text1"
local:TextBoxBehavior.BehavoirOnGotFocus="SelectAll"
local:FrameworkElementBehavior.IsFocused="True"/>
<TextBlock Text="フォーカス時、最も→にカレット"/>
<TextBox Text="Text2"
local:TextBoxBehavior.BehavoirOnGotFocus="CaretRight"/>
<TextBlock Text="フォーカス時、最も←にカレット"/>
<TextBox Text="Text3"
local:TextBoxBehavior.BehavoirOnGotFocus="CaretLeft"/>
<TextBox Text="Text4"/>
<Button local:FocusMoveBehavior.Excluded="True" Content="Button1"/>
</StackPanel>
</Grid>
</Window>

FrameworkElementBehavior.IsFocusedを設定すると、起動時にそのコントロールにフォーカスが当たる。
動きは↓のような感じになる。
20120713
ただし、マウスによるフォーカスには効果がない。あくまでTabキー等を使ってフォーカスをあてた時の挙動が変わるだけだ。
マウス系はどうしようもないので、現在は放ってある。
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


サイドバー背後固定表示サンプル

当ブログに書かれたソースコードは流用自由です。

バグ、スペルミス等はありうる事です。

ご利用の際は自己責任でお願いしますm(_ _)m