フォーカスの概要
更新 : 2007 年 11 月
WPF では、キーボード フォーカスと論理フォーカスという、フォーカスに関する 2 つの主要な概念があります。キーボード フォーカスはキーボード入力を受け取る要素を表し、論理フォーカスはフォーカスを持つフォーカス範囲内の要素を表します。これらの概念については、この概要で詳しく説明します。フォーカスを取得可能な領域を複数持つ複雑なアプリケーションを作成する場合は、これらの概念の違いを理解することが重要です。
フォーカス管理に関与する主要なクラスには、Keyboard クラス、FocusManager クラス、および UIElement や ContentElement などの基本要素クラスがあります。基本要素の詳細については、「基本要素の概要」を参照してください。
Keyboard クラスは主にキーボード フォーカスに関連し、FocusManager は主に論理フォーカスに関連しますが、これは絶対的な区別ではありません。キーボード フォーカスを持つ要素は論理フォーカスも持ちますが、論理フォーカスを持つ要素は必ずしもキーボード フォーカスを持ちません。Keyboard クラスを使用してキーボード フォーカスを持つ要素を設定したときには、要素に論理フォーカスも設定されるので、この違いがよくわかります。
このトピックには次のセクションが含まれています。
- キーボード フォーカス
- 論理フォーカス
- キーボード ナビゲーション
- プログラムによるフォーカスのナビゲーション
- フォーカス イベント
- 関連トピック
キーボード フォーカス
キーボード フォーカスは、現在キーボード入力を受け取っている要素を指します。キーボード フォーカスを持つ要素は、デスクトップ全体で 1 つしかありません。WPF では、キーボード フォーカスを持つ要素の IsKeyboardFocused は true に設定されます。Keyboard クラスの静的プロパティ FocusedElement は、現在キーボード フォーカスを持っている要素を取得します。
要素でキーボード フォーカスを取得するためには、基本要素で Focusable プロパティと IsVisible プロパティを true に設定する必要があります。Panel 基本クラスなど一部のクラスでは Focusable の既定値は false です。したがって、このような要素がキーボード フォーカスを取得できるようにする場合は、Focusable を true に設定する必要があります。
キーボード フォーカスは、要素への Tab キーでの移動や特定の要素でのマウスのクリックなど、UI でのユーザー操作を通じて取得できます。キーボード フォーカスは、Keyboard クラスで Focus メソッドを使用してプログラムにより取得することもできます。Focus メソッドは、指定された要素にキーボード フォーカスを設定しようとします。返される要素はキーボード フォーカスが設定された要素ですが、古いフォーカス オブジェクトまたは新しいフォーカス オブジェクトが要求をブロックする場合は、要求された要素とは異なる可能性があります。
Focus メソッドを使用して、キーボード フォーカスを Button に設定する例を次に示します。
private void OnLoaded(object sender, RoutedEventArgs e)
{
// Sets keyboard focus on the first Button in the sample.
Keyboard.Focus(firstButton);
}
基本要素クラスの IsKeyboardFocused プロパティは、要素にキーボード フォーカスがあるかどうかを示す値を取得します。基本要素クラスの IsKeyboardFocusWithin プロパティは、要素またはいずれかの子ビジュアル要素にキーボード フォーカスがあるかどうかを示す値を取得します。
アプリケーションの起動時に初期フォーカスを設定する場合、フォーカスを受け取る要素を PresentationSource に接続し、その要素の Focusable および IsVisible を true に設定する必要があります。初期フォーカスを設定する場所は、Loaded イベント ハンドラ内にすることをお勧めします。Dispatcher コールバックは、Invoke または BeginInvoke を呼び出して使用することもできます。
論理フォーカス
論理フォーカスとは、フォーカス範囲内の FocusManager.FocusedElement を意味します。フォーカス範囲とは、その範囲内の FocusedElement を追跡する要素です。キーボード フォーカスがフォーカス範囲を離れると、フォーカスがある要素はキーボード フォーカスを失いますが、論理フォーカスは引き続き保持します。キーボード フォーカスがフォーカス範囲に戻ると、フォーカスがある要素はキーボード フォーカスを得ます。これにより、キーボード フォーカスが複数のフォーカス範囲間で変更されても、フォーカスがフォーカス範囲に戻ると、そのフォーカス範囲内のフォーカスがある要素はキーボード フォーカスを取り戻すことができます。
アプリケーションでは、複数の要素が論理フォーカスを持つことがありますが、特定のフォーカス範囲で論理フォーカスを持つ要素は 1 つだけに限られます。
キーボード フォーカスを持つ要素は、その要素が属するフォーカス範囲の論理フォーカスを持ちます。
Extensible Application Markup Language (XAML) では、FocusManager の添付プロパティ IsFocusScope を true に設定して、要素をフォーカス範囲にすることができます。コードでは、SetIsFocusScope を呼び出して、要素をフォーカス範囲することができます。
IsFocusScope 添付プロパティを設定して、StackPanel をフォーカス範囲にする例を次に示します。
<StackPanel Name="focusScope1"
FocusManager.IsFocusScope="True"
Height="200" Width="200">
<Button Name="button1" Height="50" Width="50"/>
<Button Name="button2" Height="50" Width="50"/>
</StackPanel>
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);
GetFocusScope は、指定した要素のフォーカス範囲を返します。
既定でフォーカス範囲になる、WPF のクラスは、Window、MenuItem、ToolBar、および ContextMenu です。
GetFocusedElement は、指定したフォーカス範囲のフォーカスがある要素を取得します。SetFocusedElement は、指定したフォーカス範囲内にフォーカスがある要素を設定します。SetFocusedElement は通常、初期フォーカスを持つ要素を設定するために使用されます。
フォーカス範囲にフォーカスを持つ要素を設定し、フォーカス範囲のフォーカスを持つ要素を取得する例を次に示します。
// Sets the focused element in focusScope1
// focusScope1 is a StackPanel.
FocusManager.SetFocusedElement(focusScope1, button2);
// Gets the focused element for focusScope 1
IInputElement focusedElement = FocusManager.GetFocusedElement(focusScope1);
キーボード ナビゲーション
KeyboardNavigation クラスは、ナビゲーション キーのいずれかが押されたときに、既定のキーボード フォーカスのナビゲーションを実装します。ナビゲーション キーとは、Tab、Shift + Tab、Ctrl + Tab、Ctrl + Shift + Tab、上方向、下方向、左方向、および右方向の各キーを指します。
ナビゲーション コンテナのナビゲーション動作は、添付 KeyboardNavigation プロパティの TabNavigation、ControlTabNavigation、および DirectionalNavigation を設定することにより変更できます。これらのプロパティは KeyboardNavigationMode 型であり、指定可能な値は Continue、Local、Contained、Cycle、Once、および None です。既定値は Continue です。これは、要素がナビゲーション コンテナではないことを意味します。
複数の MenuItem オブジェクトを使用して Menu を作成する例を次に示します。Menu で、TabNavigation 添付プロパティが Cycle に設定されます。Menu 内で Tab キーを使用してフォーカスを変更すると、各要素間をフォーカスが移動し、最後の要素に達すると最初の要素にフォーカスが戻ります。
<Menu KeyboardNavigation.TabNavigation="Cycle">
<MenuItem Header="Menu Item 1" />
<MenuItem Header="Menu Item 2" />
<MenuItem Header="Menu Item 3" />
<MenuItem Header="Menu Item 4" />
</Menu>
Menu navigationMenu = new Menu();
MenuItem item1 = new MenuItem();
MenuItem item2 = new MenuItem();
MenuItem item3 = new MenuItem();
MenuItem item4 = new MenuItem();
navigationMenu.Items.Add(item1);
navigationMenu.Items.Add(item2);
navigationMenu.Items.Add(item3);
navigationMenu.Items.Add(item4);
KeyboardNavigation.SetTabNavigation(navigationMenu,
KeyboardNavigationMode.Cycle);
プログラムによるフォーカスのナビゲーション
フォーカスを操作するための追加の API には、MoveFocus と PredictFocus があります。
MoveFocus は、アプリケーション内の次の要素にフォーカスを変更します。TraversalRequest は、方向を指定するために使用されます。MoveFocus に渡された FocusNavigationDirection は、First、Last、Up、Down などの、フォーカスを移動可能な方向を指定します。
MoveFocus を使用してフォーカスがある要素を変更する例を次に示します。この例のソース コード全体については、「プログラムによるフォーカス操作のサンプル」を参照してください。
// Creating a FocusNavigationDirection object and setting it to a
// local field that contains the direction selected.
FocusNavigationDirection focusDirection = _focusMoveValue;
// MoveFocus takes a TraveralReqest as its argument.
TraversalRequest request = new TraversalRequest(focusDirection);
// Gets the element with keyboard focus.
UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
// Change keyboard focus.
if (elementWithFocus != null)
{
elementWithFocus.MoveFocus(request);
}
PredictFocus は、フォーカスが変更された場合にフォーカスを受け取るオブジェクトを返します。現在、PredictFocus でサポートされているのは、Up、Down、Left、および Right だけです。
フォーカス イベント
キーボード フォーカスに関連するイベントには、PreviewGotKeyboardFocus と GotKeyboardFocus、および PreviewLostKeyboardFocus と LostKeyboardFocus があります。イベントは、Keyboard クラスで添付イベントとして定義されますが、基本要素クラスで等価なルーティング イベントして簡単にアクセスできます。イベントの詳細については、「ルーティング イベントの概要」を参照してください。
要素がキーボード フォーカスを得ると、GotKeyboardFocus が発生します。要素がキーボード フォーカスを失うと、LostKeyboardFocus が発生します。PreviewGotKeyboardFocus イベントまたは PreviewLostKeyboardFocusEvent イベントが処理され、Handled が true に設定されると、フォーカスは変更されなくなります。
GotKeyboardFocus イベント ハンドラと LostKeyboardFocus イベント ハンドラを TextBox に添付する例を次に示します。
<Border BorderBrush="Black" BorderThickness="1"
Width="200" Height="100" Margin="5">
<StackPanel>
<Label HorizontalAlignment="Center" Content="Type Text In This TextBox" />
<TextBox Width="175"
Height="50"
Margin="5"
TextWrapping="Wrap"
HorizontalAlignment="Center"
VerticalScrollBarVisibility="Auto"
GotKeyboardFocus="TextBoxGotKeyboardFocus"
LostKeyboardFocus="TextBoxLostKeyboardFocus"
KeyDown="SourceTextKeyDown"/>
</StackPanel>
</Border>
TextBox がキーボード フォーカスを取得すると、TextBox の Background プロパティが LightBlue に変更されます。
private void TextBoxGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
TextBox source = e.Source as TextBox;
if (source != null)
{
// Change the TextBox color when it obtains focus.
source.Background = Brushes.LightBlue;
// Clear the TextBox.
source.Clear();
}
}
TextBox がキーボード フォーカスを失うと、TextBox の Background プロパティが白に戻ります。
private void TextBoxLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
TextBox source = e.Source as TextBox;
if (source != null)
{
// Change the TextBox color when it loses focus.
source.Background = Brushes.White;
// Set the hit counter back to zero and updates the display.
this.ResetCounter();
}
}
論理フォーカスに関連するイベントには、GotFocus および LostFocus があります。これらのイベントは、FocusManager で添付イベントとして定義されますが、FocusManager は CLR イベント ラッパーを公開しません。UIElement および ContentElement は、これらのイベントをより便利に公開しています。