フォーカスの概要

WPF では、キーボード フォーカスと論理フォーカスという、フォーカスに関する 2 つの主要な概念があります。 キーボード フォーカスはキーボード入力を受け取る要素を表し、論理フォーカスはフォーカスを持つフォーカス範囲内の要素を表します。 これらの概念については、この概要で詳しく説明します。 フォーカスを取得可能な領域を複数持つ複雑なアプリケーションを作成する場合は、これらの概念の違いを理解することが重要です。

フォーカス管理に関与する主要なクラスには、Keyboard クラス、FocusManager クラス、および UIElementContentElement などの基本要素クラスがあります。 基本要素の詳細については、「基本要素の概要」を参照してください。

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 Sub OnLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Sets keyboard focus on the first Button in the sample.
            Keyboard.Focus(firstButton)
        End Sub
private void OnLoaded(object sender, RoutedEventArgs e)
{
    // Sets keyboard focus on the first Button in the sample.
    Keyboard.Focus(firstButton);
}

基本要素クラスの IsKeyboardFocused プロパティは、要素にキーボード フォーカスがあるかどうかを示す値を取得します。 基本要素クラスの IsKeyboardFocusWithin プロパティは、要素またはいずれかの子ビジュアル要素にキーボード フォーカスがあるかどうかを示す値を取得します。

アプリケーションの起動時に初期フォーカスを設定する場合、フォーカスを受け取る要素は、アプリケーションによって読み込まれる初期ウィンドウのビジュアル ツリーに含まれていて、FocusableIsVisible が 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>
            Dim focuseScope2 As New StackPanel()
            FocusManager.SetIsFocusScope(focuseScope2, True)
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);

GetFocusScope は、指定した要素のフォーカス範囲を返します。

既定でフォーカス範囲になる、WPF のクラスは、WindowMenuItemToolBar、および 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
            Dim focusedElement As IInputElement = FocusManager.GetFocusedElement(focusScope1)
// 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 プロパティの TabNavigationControlTabNavigation、および DirectionalNavigation を設定することにより変更できます。 これらのプロパティは KeyboardNavigationMode 型であり、指定可能な値は ContinueLocalContainedCycleOnce、および 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>
            Dim navigationMenu As New Menu()
            Dim item1 As New MenuItem()
            Dim item2 As New MenuItem()
            Dim item3 As New MenuItem()
            Dim item4 As New MenuItem()

            navigationMenu.Items.Add(item1)
            navigationMenu.Items.Add(item2)
            navigationMenu.Items.Add(item3)
            navigationMenu.Items.Add(item4)

            KeyboardNavigation.SetTabNavigation(navigationMenu, KeyboardNavigationMode.Cycle)
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 には、MoveFocusPredictFocus があります。

MoveFocus は、アプリケーション内の次の要素にフォーカスを変更します。 TraversalRequest は、方向を指定するために使用されます。 MoveFocus に渡された FocusNavigationDirection は、FirstLastUpDown などの、フォーカスを移動できる方向を指定します。

MoveFocus を使用してフォーカスがある要素を変更する例を次に示します。

            ' Creating a FocusNavigationDirection object and setting it to a
            ' local field that contains the direction selected.
            Dim focusDirection As FocusNavigationDirection = _focusMoveValue

            ' MoveFocus takes a TraveralReqest as its argument.
            Dim request As New TraversalRequest(focusDirection)

            ' Gets the element with keyboard focus.
            Dim elementWithFocus As UIElement = TryCast(Keyboard.FocusedElement, UIElement)

            ' Change keyboard focus.
            If elementWithFocus IsNot Nothing Then
                elementWithFocus.MoveFocus(request)
            End If
// 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 でサポートされているのは、UpDownLeft、および Right だけです。

フォーカス イベント

キーボード フォーカスに関連するイベントには、PreviewGotKeyboardFocusGotKeyboardFocus、および PreviewLostKeyboardFocusLostKeyboardFocus があります。 イベントは、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 がキーボード フォーカスを取得すると、TextBoxBackground プロパティが LightBlue に変更されます。

        Private Sub TextBoxGotKeyboardFocus(ByVal sender As Object, ByVal e As KeyboardFocusChangedEventArgs)
            Dim source As TextBox = TryCast(e.Source, TextBox)

            If source IsNot Nothing Then
                ' Change the TextBox color when it obtains focus.
                source.Background = Brushes.LightBlue

                ' Clear the TextBox.
                source.Clear()
            End If
        End Sub
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 がキーボード フォーカスを失うと、TextBoxBackground プロパティが白に戻ります。

        Private Sub TextBoxLostKeyboardFocus(ByVal sender As Object, ByVal e As KeyboardFocusChangedEventArgs)
            Dim source As TextBox = TryCast(e.Source, TextBox)

            If source IsNot Nothing Then
                ' Change the TextBox color when it loses focus.
                source.Background = Brushes.White

                ' Set the  hit counter back to zero and updates the display.
                Me.ResetCounter()
            End If
        End Sub
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 イベント ラッパーを公開しません。 これらのイベントは、UIElementContentElement によって、より使いやすい形で公開されます。

参照

参照

FocusManager

UIElement

ContentElement

概念

入力の概要

基本要素の概要