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

で説明できていなかった、カスタム系の話。
任意の位置にカレットを配置させようと考えた時、思いつけたのが

・インデックスを指定しよう。
・特定の文字を指定しよう。

くらいだった。各々の用途向けに、添付プロパティを実装する。

/// <summary>
/// フォーカス取得時のカレット位置を取得します。<br/>
/// </summary>
/// <remarks>
/// BehavoirOnGotFocusプロパティと連携します。<br/>
/// BehaviorOnGotFocusプロパティにカスタム(Optional)が設定された時に使われます<br/>
/// </remarks>
/// <param name="obj">対象オブジェクト</param>
/// <returns>カレット位置</returns>
public static int GetCaretIndexOnFocus(DependencyObject obj) {
return (int)obj.GetValue(CaretIndexOnFocusProperty);
}

/// <summary>
/// フォーカス取得時のカレット位置を設定します。<br/>
/// </summary>
/// <remarks>
/// BehavoirOnGotFocusプロパティと連携します。<br/>
/// BehaviorOnGotFocusプロパティにカスタム(Optional)が設定された時に使われます<br/>
/// </remarks>
/// <param name="obj">対象オブジェクト</param>
/// <param name="value">カレット位置</param>
public static void SetCaretIndexOnFocus(DependencyObject obj, int value) {
obj.SetValue(CaretIndexOnFocusProperty, value);
}

/// <summary>フォーカス取得時のカレット位置(BehaviorOnGotFocus.Optional用)</summary>
public static readonly DependencyProperty CaretIndexOnFocusProperty =
DependencyProperty.RegisterAttached("CaretIndexOnFocus", typeof(int),
typeof(TextBoxBehavior),
new UIPropertyMetadata(-1));

/// <summary>
/// カレット移動時に起点となる文字を取得します。<br/>
/// </summary>
/// <remarks>
/// BehavoirOnGotFocusプロパティと連携します。<br/>
/// BehaviorOnGotFocusプロパティにカスタム(Optional)が設定された時に使われます<br/>
/// </remarks>
/// <param name="obj">対象オブジェクト</param>
/// <returns>起点となる文字</returns>
public static string GetBaseCharOfCaret(DependencyObject obj) {
return (string)obj.GetValue(BaseCharOfCaretProperty);
}

/// <summary>
/// カレット移動時に起点となる文字を設定します。<br/>
/// </summary>
/// <remarks>
/// BehavoirOnGotFocusプロパティと連携します。<br/>
/// BehaviorOnGotFocusプロパティにカスタム(Optional)が設定された時に使われます<br/>
/// </remarks>
/// <param name="obj">対象オブジェクト</param>
/// <param name="value">起点となる文字</param>
public static void SetBaseCharOfCaret(DependencyObject obj, string value) {
obj.SetValue(BaseCharOfCaretProperty, value);
}

/// <summary>カレット移動時に起点となる文字</summary>
public static readonly DependencyProperty BaseCharOfCaretProperty =
DependencyProperty.RegisterAttached("BaseCharOfCaret", typeof(string),
typeof(TextBoxBehavior), new UIPropertyMetadata(null));

TxtBox_GotKeyboardFocusメソッドに実装を追加する。

/// <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:
//カスタム
//カレットの位置
var caretIndex = GetCaretIndexOnFocus(txtBox);
//基点とする文字
string baseChar = GetBaseCharOfCaret(txtBox);

if (string.IsNullOrEmpty(baseChar)) {
//基点とする文字が未設定
//→caretIndexの値でカレットを移動させます。
if (caretIndex >= 0) {
txtBox.CaretIndex = caretIndex;
}

} else {
//基点とする文字が設定されている
//テキスト内の文字を検索して、位置を特定します。
//存在すれば、caretIndexをオフセット的な扱いにして移動させます。
var idx = txtBox.Text.IndexOf(baseChar);

if (idx >= 0) {
txtBox.CaretIndex = Math.Max(0, idx + caretIndex);
} else {
txtBox.CaretIndex = Math.Max(0, txtBox.Text.Length);
}
}
break;
default:
break;
}
}

カスタムの使い方的には、

数値用の項目で、フォーカス時のカレット位置を小数点に置きたい

とか。

<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"/>
<TextBlock Text="フォーカス時、ドット(.)の位置にカレット"/>

<TextBox Text="Text4"
local:TextBoxBehavior.BehavoirOnGotFocus="CaretOptional"
local:TextBoxBehavior.BaseCharOfCaret="."
local:TextBoxBehavior.CaretIndexOnFocus="0"
/>

<Button local:FocusMoveBehavior.Excluded="True" Content="Button1"/>
</StackPanel>
</Grid>
</Window>


フォーカス時は↓のようになる。
20120713_2
こうすることで、いちいち移動しなくても、整数部の編集に入れるかな~とか。
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


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

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

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

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