Поделиться через


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

Приложение 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 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 для классов базовых элементов получает значение, указывающее, имеет ли элемент, или один из его видимых дочерних элементов, фокус ввода.

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

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

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

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

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

Элемент может быть включен в область фокуса в Extensible Application Markup Language (XAML) путем задания для вложенного свойства зависимостей IsFocusScope объекта FocusManager значения 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>
            Dim focuseScope2 As New StackPanel()
            FocusManager.SetIsFocusScope(focuseScope2, True)
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
            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 TabNavigation ControlTabNavigation и DirectionalNavigation. Эти свойства являются объектом KeyboardNavigationMode типа, и возможными значениями являются: Continue, Local, Contained, Cycle, Once и None. Значение по умолчанию — Continue, которое означает, что элемент не является контейнером навигации.

В следующем примере создается объект Menu с объектами MenuItem. Для вложенного свойства TabNavigation в объекте Menu устанавливается значение Cycle. При изменении фокуса с помощью клавиши 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>
            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 для работы с фокусом являются MoveFocus и PredictFocus.

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

В следующем примере используется метод 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 возвращает объект, который мог бы получить фокус, если фокус будет изменен. В текущий момент только свойства 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 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 теряет фокус ввода, свойство Background объекта TextBox снова становится пустым.

        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. Элементы UIElement и ContentElement предоставляют эти события более удобным образом.

См. также

Ссылки

FocusManager

UIElement

ContentElement

Основные понятия

Общие сведения о входных данных

Общие сведения о базовых элементах