VM側から特定コントロールにフォーカスを当てる(壱)。

入力チェック等で、どこの項目がエラーになっているかを表示した後で、当該のコントロールにフォーカスを当てると、そのまま入力修正に入る事ができる。
WPFのコントロールにもFocusというメソッドがあるが、IsFocusedというプロパティは残念ながらない。
フォーカスにも、キーボードフォーカスとか、論理フォーカスとかあって、ややこしい。
フォーカスの概要
VM側から制御しようと思うなら、プロパティ値の変更をトリガーにして、フォーカスを当てる、というのが一般的かな。Messengerがあるなら、それも可能かもしれないけど。とりあえず
プロパティを用意する。
用意したプロパティをトリガーにしてフォーカスを当てるようにする。
を実装しようと思う。
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}"
>
<StackPanel>
<TextBox MinWidth="100" Name="Text1" Text="Text1">
<TextBox MinWidth="100" Name="Text2" Text="Text2">
<TextBox MinWidth="100" Name="Text3" Text="Text3">
<Button Content="Text1へフォーカス" Command="{Binding Focus1Command}"/>
<Button Content="Text2へフォーカス" Command="{Binding Focus2Command}"/>
<Button Content="Text3へフォーカス" Command="{Binding Focus3Command}"/>
</StackPanel>
</Window>
Textとボタンをそれぞれ3つ用意し、各ボタンを押すことで、対応するテキストボックスにフォーカスを当てるように実装する。
○プロパティを用意

/// <summary>Text1フォーカス用変数</summary>
private bool isText1Focus_;

/// <summary>
/// Text1フォーカス用変数を取得|設定します。
/// </summary>
public bool IsText1Focus {
get {return isText1Focus_;}
set {
if (isText1Focus_ != value) {
isText1Focus_ = value;
this.NotifyPropertyChanged("IsText1Focus");
}
}
}
これを1~3用に用意する。
○コマンド実装
各々のボタン用にコマンドを用意する。

/// <summary>Text1へフォーカス</summary>
private RelayCommand focus1Command_;

/// <summary>
/// Text1へフォーカス用コマンドを取得します。
/// </summary>
public ICommand Focus1Command {
get {return focus1Command_;}
}
これを1~3まで用意する。
○Window用VM生成時に、コマンドのインスタンスも生成する。

focus1Command_ = new RelayCommand(this.ExecuteFocus1);
focus2Command_ = new RelayCommand(this.ExecuteFocus2);
focus3Command_ = new RelayCommand(this.ExecuteFocus3);
○各々のメソッドで、フォーカス用変数の値を変える。

/// <summary>
/// 「Text1へフォーカス」コマンド実行用メソッド
/// </summary>
/// <param name="parameter">コマンドパラメータ</param>
private void ExecuteFocus1(object parameter) {
IsText1Focus = false;
IsText1Focus = true;
return;
}
一旦falseにしてtrueに変えるのは、trueからfalseに変えるタイミングが見つからなかったので。
○このプロパティに反応するStyleを定義する。

<TextBox MinWidth="100" Name="Text1" Text="Text1">
<TextBox.Resources>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IsText1Focus}" Value="True">
<Setter Property="FocusManager.FocusedElement"
Value="{Binding ElementName=Text1}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Resources>
</TextBox>
FocusManagerというクラスは、名前の通り、フォーカスを管理するクラス。
FocusManager クラス
FocusManagerが持つFocusedElementプロパティを使う事で実現できる。データバインディングを使って、フォーカスを当てたいコントロールそのものをValueに渡す。
まとめと課題
・VM側で用意したプロパティ値の変更をトリガーにフォーカスを当てる。
・トリガーに使うだけであって、現在のフォーカス状態を示しているわけではない。
・Styleは使い回しが効かないので、いちいち書く必要がある。
・プロパティ値もfalseに戻してからtrueに設定するという実装を意図的に行う必要がある。
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 2 | トラックバック: 0


この記事へのコメント

No title
Messengerがあるなら、それも可能かもしれないけど…という文言は見かけるのですが実際のソースは何処にも載っていません。どのような記述になるのでしょうか?
Re: No title
私自身もMessengerに対する知識(実装経験)はないです。すみません。
実装されたコードを探すなら、CodeProjectか、CodePlexとかが良いかなと思います。
WPFに関する記事が多いのは、英語サイトなので、ググる時も英語で検索とかすると結構ヒットします。

コメントの投稿

非公開コメント


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

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

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

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