Q044. WPF で Tab オーダーを細かく設定する方法は?
A. Windows Forms なら、デザイナでフォームを開き、「表示」→「タブオーダー」で現在のタブインデックスが表示され、クリック順でタブインデックスを設定することができます。
関連記事 : Windows アプリケーションの利点
関連記事 : コントロールのTabIndex順で処理したいことってあるよね。階層のTabIndexを表現してみよう。
残念なことに WPF にはそのような便利な機能はありません。WPF の場合、タブインデックスは基本的に XAML の要素順になります。
任意にタブオーダーを指定したいなら TabIndex プロパティを明示的に設定する方法もありますが、UserControl にTabIndex を設定すると、パレント側の TabIndex と衝突し想定外のコントロールにフォーカスがジャンプしたり、同じ UserContorol を複数貼り付けると、UserControl内の同じコントロールでタブ遷移を行ってしまう等、想定外の事態が発生します。
例えば以下のような UserContorol があるとします。各コントロールには 明示的に TabIndex が設定されています。
<UserControl x:Class="UserControl1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="200" d:DesignWidth="150" > <StackPanel > <TextBox Name="TextBox1" Height="20" TabIndex="1" /> <TextBox Name="TextBox2" Height="20" TabIndex="2" /> <TextBox Name="TextBox3" Height="20" TabIndex="3" /> <Button Name="Button1" Height="20" Content="Button1" TabIndex="4" /> <Button Name="Button2" Height="20" Content="Button2" TabIndex="5" /> </StackPanel> </UserControl>
この UserControl を Window に二つ配置します。
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="250" Width="300" xmlns:my="clr-namespace:WpfApplication1"> <Grid> <my:UserControl1 HorizontalAlignment="Left" Margin="30,40,0,0" x:Name="UserControl11" VerticalAlignment="Top" /> <my:UserControl1 HorizontalAlignment="Left" Margin="90,40,0,0" x:Name="UserControl12" VerticalAlignment="Top" /> </Grid> </Window>
タブ遷移は UserControl 内を移動せず、以下のように Window に配置した二つのUserContorl 間で交互に移動します。これでは話になりません。('A`)
UserControl11.TextBox1 → UserControl12.TextBox1 → UserControl11.TextBox2 → UserControl12.TextBox2 ・・・
そこで XAML で TabIndex を細かく制御するには KeyboardNavigation.TabNavigation を使うといいみたいです。
コントロールのコンテナである StackPanel に添付プロパティ KeyboardNavigation.TabNavigation を設定します。KeyboardNavigation.TabNavigation に Local を指定すると、タブインデックスはコンテナ内で優先され、要素の終端に達するとコンテナからフォーカスが離れます。
<UserControl x:Class="UserControl1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="200" d:DesignWidth="150" > <StackPanel KeyboardNavigation.TabNavigation ="Local" > <TextBox Name="TextBox1" Height="20" TabIndex="1" /> <TextBox Name="TextBox2" Height="20" TabIndex="2" /> <TextBox Name="TextBox3" Height="20" TabIndex="3" /> <Button Name="Button1" Height="20" Content="Button1" TabIndex="4" /> <Button Name="Button2" Height="20" Content="Button2" TabIndex="5" /> </StackPanel> </UserControl>
これでタブフォーカスは以下のように UserControl 内を移動するようになりました。
UserControl11.TextBox1 → UserControl11.TextBox2 → UserControl11.TextBox3 → UserControl11.Button1 ・・・
関連記事 : KeyboardNavigationMode 列挙体