Compartilhar via


Visão geral do foco

No WPF, há dois conceitos principais que pertencem ao foco: foco do teclado e foco lógico. O foco do teclado refere-se ao elemento que recebe a entrada do teclado, e o foco lógico refere-se ao elemento em um escopo de foco que está em foco. Esses conceitos são discutidos em detalhes nesta visão geral. Entender a diferença nesses conceitos é importante para a criação de aplicativos complexos que têm várias regiões em que o foco pode ser obtido.

As classes principais que participam do gerenciamento de foco são a Keyboard classe, a FocusManager classe e as classes de elemento base, como UIElement e ContentElement. Para obter mais informações sobre os elementos base, consulte a Visão geral dos elementos base.

A Keyboard classe se preocupa principalmente com o foco do teclado e se preocupa principalmente com o FocusManager foco lógico, mas essa não é uma distinção absoluta. Um elemento que tem o foco do teclado também terá foco lógico, mas um elemento que tem foco lógico não necessariamente tem o foco do teclado. Isso é evidente quando você usa a Keyboard classe para definir o elemento que tem o foco do teclado, pois ele também define o foco lógico no elemento.

Foco do teclado

O foco do teclado refere-se ao elemento que está recebendo entrada de teclado no momento. Pode haver apenas um elemento em toda a área de trabalho que tenha o foco do teclado. No WPF, o elemento que tem foco no teclado terá IsKeyboardFocused definido como true. A propriedade FocusedElement estática na Keyboard classe obtém o elemento que atualmente tem o foco do teclado.

Para que um elemento obtenha o foco do teclado, as propriedades Focusable e IsVisible nos elementos base devem ser definidas como true. Algumas classes, como a Panel classe base, têm Focusable definido como false por padrão; portanto, você deve definir Focusable para true se quiser que esse elemento possa obter o foco do teclado.

O foco do teclado pode ser obtido por meio da interação do usuário com a interface do usuário, como navegar até um elemento via tabulação ou clicando em determinados elementos. O foco do teclado também pode ser obtido programaticamente usando o método Focus na classe Keyboard. O método Focus tenta dar o foco do teclado ao elemento especificado. O elemento retornado é o elemento que tem o foco do teclado, que pode ser um elemento diferente do solicitado se o objeto de foco antigo ou novo bloquear a solicitação.

O exemplo a seguir usa o método Focus para definir o foco do teclado em um 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

A IsKeyboardFocused propriedade nas classes de elemento base obtém um valor que indica se o elemento tem o foco do teclado. A propriedade IsKeyboardFocusWithin nas classes de elementos base obtém um valor que indica se o elemento ou qualquer um dos seus elementos filhos visuais está focado no teclado.

Ao definir o foco inicial na inicialização do aplicativo, o elemento para receber o foco deve estar na árvore visual da janela inicial carregada pelo aplicativo e o elemento deve ter Focusable e IsVisible definido como true. O local recomendado para definir o foco inicial está no Loaded manipulador de eventos. Um Dispatcher retorno de chamada também pode ser usado chamando Invoke ou BeginInvoke.

Foco Lógico

O foco lógico refere-se ao FocusManager.FocusedElement dentro de um escopo de foco. Um escopo de foco é um elemento que mantém o FocusedElement dentro de seu escopo. Quando o foco do teclado sair de um escopo de foco, o elemento focalizado perderá o foco do teclado, mas manterá o foco lógico. Quando o foco do teclado retornar ao escopo de foco, o elemento que está focalizado receberá o foco do teclado. Isso permite que o foco do teclado seja alterado entre vários escopos de foco, mas garante que o elemento focado no escopo de foco recupere o foco do teclado quando o foco retornar ao escopo de foco.

Pode haver vários elementos que têm foco lógico em um aplicativo, mas pode haver apenas um elemento que tenha foco lógico em um escopo de foco específico.

Um elemento que tem o foco do teclado tem foco lógico para o escopo de foco ao qual pertence.

Um elemento pode ser transformado em um escopo de foco em XAML (Extensible Application Markup Language) definindo a FocusManager propriedade IsFocusScope anexada como true. No código, um elemento pode ser transformado em um escopo de foco chamando SetIsFocusScope.

O exemplo a seguir transforma o StackPanel em um escopo de foco ao definir a propriedade IsFocusScope anexada.

<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 retorna o escopo de foco para o elemento especificado.

As classes no WPF que são escopos de foco por padrão são Window, MenuItem, ToolBare ContextMenu.

GetFocusedElement obtém o elemento focado para o escopo de foco especificado. SetFocusedElement define o elemento focado no escopo de foco especificado. SetFocusedElement normalmente é usado para definir o elemento focalizado inicial.

O exemplo a seguir define o elemento focado em um escopo de foco e obtém o elemento focalizado de um escopo de foco.

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

Navegação por teclado

A KeyboardNavigation classe é responsável por implementar a navegação de foco do teclado padrão quando uma das teclas de navegação é pressionada. As chaves de navegação são: TECLAS TAB, SHIFT+TAB, CTRL+TAB, CTRL+SHIFT+TAB, UPARROW, DOWNARROW, LEFTARROW e RIGHTARROW.

O comportamento de navegação de um contêiner de navegação pode ser alterado definindo as propriedades anexadas KeyboardNavigation, TabNavigation, ControlTabNavigation e DirectionalNavigation. Essas propriedades são do tipo KeyboardNavigationMode e os valores possíveis sãoContinue, , Local, Contained, , Cyclee OnceNone. O valor padrão é Continue, o que significa que o elemento não é um contêiner de navegação.

O exemplo a seguir cria um Menu com vários MenuItem objetos. A propriedade anexada TabNavigation está configurada Cycle no Menu. Quando o foco for alterado usando a tecla Tab dentro do Menu, o foco será movido de cada elemento, e, quando o último elemento for atingido, o foco retornará ao primeiro elemento.

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

APIs adicionais para trabalhar com foco são as MoveFocus e PredictFocus.

MoveFocus altera o foco para o próximo elemento no aplicativo. Um TraversalRequest é usado para especificar a direção. A FocusNavigationDirection passada para MoveFocus especifica as diferentes direções para as quais o foco pode ser movido, como First, Last, Up e Down.

O exemplo a seguir usa MoveFocus para alterar o elemento focalizado.

// 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 retorna o objeto que receberia o foco se o foco fosse alterado. Atualmente, somente Up, Down, Left, e Right são suportados por PredictFocus.

Eventos de foco

Os eventos relacionados ao foco do teclado são PreviewGotKeyboardFocus, GotKeyboardFocus e PreviewLostKeyboardFocus, LostKeyboardFocus. Os eventos são definidos como eventos anexados na Keyboard classe, mas são mais facilmente acessíveis como eventos roteados equivalentes nas classes de elemento base. Para obter mais informações sobre eventos, consulte a Visão geral de eventos roteados.

GotKeyboardFocus é gerado quando o elemento obtém o foco do teclado. LostKeyboardFocus é gerado quando o elemento perde o foco do teclado. Se o PreviewGotKeyboardFocus evento ou o PreviewLostKeyboardFocusEvent evento for tratado e Handled estiver definido como true, o foco não será alterado.

O exemplo a seguir anexa GotKeyboardFocus e LostKeyboardFocus manipuladores de eventos a um 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>

Quando o TextBox obtém foco do teclado, a propriedade Background do TextBox é alterada para 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

Quando o foco do teclado é perdido, a propriedade TextBox do Background é alterada de volta para branco.

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

Os eventos relacionados ao foco lógico são GotFocus e LostFocus. Esses eventos são definidos no FocusManager como eventos anexados, mas o FocusManager não expõe os encapsulamentos de eventos CLR. UIElement e ContentElement expõem esses eventos de forma mais conveniente.

Consulte também