Общие сведения о фокусе

Существует два основных понятия, относящихся к фокусу в WPF: фокус клавиатуры и логический фокус. Фокус клавиатуры ссылается на элемент, получающий ввод с клавиатуры, а логический фокус ссылается на элемент в области фокуса, имеющий фокус. Эти понятия подробно освещаются в этом обзоре. Важно понимать разницу между этими понятиями, чтобы создавать сложные приложения с несколькими областями, в которых можно получить фокус.

Основными классами, участвующими в управлении фокусом, являются Keyboard класс, FocusManager класс и классы базовых элементов, такие как UIElement и ContentElement . Дополнительные сведения о базовых элементах см. в разделе Общие сведения о базовых элементах.

KeyboardКласс имеет дело в основном с фокусом клавиатуры, и в FocusManager основном он касается логического фокуса, но это не абсолютное отличие. Элемент, имеющий фокус клавиатуры, также будет иметь логический фокус, но элемент, имеющий логический фокус, не обязательно будет иметь фокус клавиатуры. Это очевидно при использовании Keyboard класса для задания элемента с фокусом клавиатуры, для этого также устанавливается логический фокус на элемент.

Фокус клавиатуры

Фокус клавиатуры относится к элементу, получающему ввод с клавиатуры. На всем рабочем столе может быть только один элемент, в котором находится фокус клавиатуры. В WPF элемент, имеющий фокус клавиатуры, будет иметь IsKeyboardFocused значение true . Статическое свойство FocusedElement Keyboard класса получает элемент, который в данный момент имеет фокус клавиатуры.

Чтобы элемент мог получить фокус клавиатуры, Focusable IsVisible Свойства и базовых элементов должны иметь значение true . Некоторые классы, например Panel базовый класс, по Focusable умолчанию имеют значение, false поэтому необходимо задать значение, если необходимо, чтобы Focusable true такой элемент мог получить фокус клавиатуры.

Фокус клавиатуры можно получить с помощью взаимодействия пользователя с UI, например перехода к элементу или щелчка мышью определенных элементов. Фокус клавиатуры можно также получить программно с помощью Focus метода Keyboard класса. FocusМетод пытается присвоить заданному элементу фокус клавиатуры. Возвращаемый элемент — это элемент, имеющий фокус клавиатуры, который может отличаться от запрошенного, если старый или новый объект фокуса блокирует запрос.

В следующем примере используется Focus метод для установки фокуса клавиатуры на Button .

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

IsKeyboardFocusedСвойство в классах базовых элементов получает значение, указывающее, имеет ли элемент фокус клавиатуры. IsKeyboardFocusWithinСвойство в классах базовых элементов получает значение, указывающее, имеет ли элемент фокус клавиатуры у элемента или одного из его визуальных дочерних элементов.

При установке начального фокуса при запуске приложения элемент для получения фокуса должен находиться в визуальном дереве исходного окна, загруженного приложением, а элемент должен иметь Focusable и иметь IsVisible значение true . Рекомендуемое место для установки начального фокуса находится в Loaded обработчике событий. DispatcherОбратный вызов может также использоваться путем вызова метода Invoke или BeginInvoke .

Логический фокус

Логический фокус относится к элементу FocusManager.FocusedElement в области фокуса. Область фокуса — это элемент, который отслеживает в FocusedElement пределах его области. Когда фокус клавиатуры покидает область фокуса, элемент с фокусом теряет фокус клавиатуры, но сохраняет логический фокус. При возвращении фокуса клавиатуры в область фокуса элемент с логическим фокусом получит фокус клавиатуры. Это позволяет переносить фокус клавиатуры между несколькими областями фокуса, но гарантирует, что элемент с фокусом в области фокуса останется элементом с фокусом клавиатуры, когда фокус вернется в эту область.

В приложении может быть несколько элементов, имеющих логический фокус, но в отдельной области фокуса может быть только один элемент, имеющий логический фокус.

Элемент, имеющий фокус клавиатуры, имеет логический фокус для области фокуса, которой он принадлежит.

Элемент можно превратить в область фокуса в Язык XAML , установив FocusManager для присоединенного свойства значение IsFocusScope true . В коде элемент можно превратить в область фокуса путем вызова SetIsFocusScope .

В следующем примере выполняется преобразование StackPanel в область фокуса путем установки IsFocusScope присоединенного свойства.

<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);
Dim focuseScope2 As 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);
' 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)

Навигация с помощью клавиатуры

KeyboardNavigationКласс отвечает за реализацию навигации фокуса клавиатуры по умолчанию при нажатии одной из клавиш навигации. Клавиши навигации: TAB, SHIFT+TAB, CTRL+TAB, CTRL+SHIFT+TAB, стрелка вверх, стрелка вниз, стрелка влево и стрелка вправо.

Поведение навигации контейнера навигации можно изменить, задав вложенные KeyboardNavigation свойства, TabNavigation ControlTabNavigation и DirectionalNavigation . Эти свойства имеют тип, KeyboardNavigationMode а возможные значения: Continue , Local ,, Contained , Cycle Once и None . Значение по умолчанию — Continue , то есть элемент не является контейнером навигации.

В следующем примере создается объект Menu с несколькими MenuItem объектами. TabNavigationПрисоединенное свойство устанавливается в значение Cycle On Menu . Когда фокус изменяется с помощью клавиши TAB в Menu , фокус перемещается с каждого элемента, а при достижении последнего элемента фокус вернется к первому элементу.

<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);
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)

Дополнительным API для работы с фокусом являются MoveFocus и PredictFocus .

MoveFocus изменяет фокус на следующий элемент в приложении. TraversalRequestДля указания направления используется. FocusNavigationDirectionПереданный метод MoveFocus задает различные направления, на которые может перемещаться фокус, First например Last , Up и Down .

В следующем примере метод используется MoveFocus для изменения элемента с элементом «Focus».

// 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);
}
' 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

PredictFocus Возвращает объект, который получит фокус, если фокус был изменен. В настоящее время Up поддерживаются только,, Down Left и Right PredictFocus .

События фокуса

События, связанные с фокусом клавиатуры: 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 получает фокус клавиатуры, Background свойство объекта TextBox изменяется на 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();
    }
}
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

Когда TextBox фокус клавиатуры теряется, Background свойство объекта TextBox изменяется обратно на белый.

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();
    }
}
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

Событиями, связанными с логическим фокусом, являются GotFocus и LostFocus . Эти события определяются в FocusManager присоединенных событиях, но не FocusManager предоставляют оболочки событий CLR. UIElement и ContentElement предоставляют более удобный доступ к этим событиям.

См. также раздел