(XAML#11)「フォーカスの設定」
Windows フォームでは、ウィンドウを表示すると、通常、先頭のコントロールにフォーカスがあります。WPF では、デフォルトではそのような動作になっていません。初期フォーカスを特定のコントロールに設定したい場合、Loaded イベントハンドラーなどで明示的に指定する必要があります。たとえば、次のように記述できます。
[XAML]
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="325" Width="525"
Loaded="Window_Loaded">
<StackPanel>
<TextBox x:Name="tbox1" />
<TextBox x:Name="tbox2" />
<TextBox x:Name="tbox3" />
</StackPanel>
</Window>
[コード]
private void Window_Loaded(object sender, RoutedEventArgs e)
{
tbox1.Focus();
}
次のように、FocusManager を使うことで、Loaded イベントを使わず XAML だけで記述することもできます。
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="325" Width="525"
FocusManager.FocusedElement="{Binding ElementName=tbox1}">
<StackPanel>
<TextBox x:Name="tbox1" />
<TextBox x:Name="tbox2" />
<TextBox x:Name="tbox3" />
</StackPanel>
</Window>
ウィンドウを表示するときに「最初のコントロールにフォーカスを設定する」という処理は、次のように記述することもできます。
[XAML]
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="325" Width="525"
Loaded="Window_Loaded">
<StackPanel>
<TextBox x:Name="tbox1" />
<TextBox x:Name="tbox2" />
<TextBox x:Name="tbox3" />
</StackPanel>
</Window>
[コード]
private void Window_Loaded(object sender, RoutedEventArgs e)
{
MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
}
MoveFocus はフォーカスを移動させるためのメソッドです。このメソッドを使って、引数となる TraversalRequest オブジェクトの内容によってフォーカスを先頭/末尾/前後/上下左右に移動します。アプリケーション中の、すべてのウィンドウでこの処理を適用させたい場合は、ウィンドウごとに記述する代わりに、これまでに紹介した「スタイル」を使うことができます。ただし、ウィンドウのスタイルは明示的に割り当てる必要があります。
[App.xaml]
<Application x:Class="WpfApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style TargetType="{x:Type Window}">
<EventSetter Event="Loaded" Handler="WindowLoaded" />
</Style>
</Application.Resources>
</Application>
[App.xaml.cs]
public partial class App : Application
{
private void WindowLoaded(object sender, RoutedEventArgs e)
{
var wnd = sender as Window;
if (wnd != null)
wnd.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
}
}
[MainWindow.xaml]
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Style="{StaticResource ResourceKey={x:Type Window}}"
Title="MainWindow" Height="325" Width="525">
...
※スタイルにキー(x:Key)を設定して、利用することもできます。
このように設定した場合、スタイルで設定した Loaded イベントハンドラーは、ウィンドウのイベントハンドラーよりも後で呼び出されます。つまり、個々のウィンドウの FocusManager.FocusedElement や Loaded イベントで初期フォーカスを設定するコントロールを指定しても、それらは Application クラスの WindowLoaded の中で上書きされてしまうということです。そのような場合は、スタイルを分けたり、ウィンドウに設定しないようにして回避してください。