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, enquanto o foco lógico refere-se ao elemento que possui o foco dentro de um escopo de 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 classe Keyboard, a classe FocusManager 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 classe Keyboard está preocupada principalmente com o foco do teclado e a FocusManager está preocupada principalmente com o 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 classe Keyboard para definir o elemento que tem o foco do teclado, pois 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 estática FocusedElement na classe Keyboard obtém o elemento que atualmente está em foco no teclado.

Para que um elemento obtenha o foco do teclado, o Focusable e as propriedades IsVisible nos elementos base devem ser definidos como true. Algumas classes, como a classe base Panel, têm Focusable definida como false por padrão; portanto, você deve definir Focusable como 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 usando a tecla Tab ou clicar 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 propriedade IsKeyboardFocused 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 elemento base obtém um valor que indica se o elemento ou qualquer um de seus elementos filho visuais tem o foco do 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 definidos como true. O local recomendado para definir o foco inicial está no manipulador de eventos Loaded. Um retorno de chamada Dispatcher também pode ser usado chamando Invoke ou BeginInvoke.

Foco Lógico

O foco lógico refere-se ao FocusManager.FocusedElement em um escopo de foco. Um escopo de foco é um elemento que mantém o controle do 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 com foco obterá 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 foco no teclado possui foco lógico dentro do escopo de foco ao qual pertence.

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

O exemplo a seguir transforma um StackPanel em um escopo de foco ao definir a propriedade anexada 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 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 focalizado 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 classe KeyboardNavigation é responsável por implementar a navegação de foco de 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 KeyboardNavigation anexadas TabNavigation, ControlTabNavigatione DirectionalNavigation. Essas propriedades são do tipo KeyboardNavigationMode e os valores possíveis são Continue, Local, Contained, Cycle, Oncee None. O valor padrão é Continue, o que significa que o elemento não é um contêiner de navegação.

O exemplo a seguir cria uma Menu com vários objetos MenuItem. A propriedade anexada TabNavigation é definida como 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)

API adicional para trabalhar com áreas de foco: MoveFocus e PredictFocus.

MoveFocus altera o foco para o próximo elemento no aplicativo. Um TraversalRequest é usado para especificar a direção. O FocusNavigationDirection passado para MoveFocus especifica que o foco de direções diferentes 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, Lefte Right são compatíveis com 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 classe Keyboard, 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 evento PreviewGotKeyboardFocus ou o evento PreviewLostKeyboardFocusEvent for tratado e Handled estiver configurado como true, então o foco não será alterado.

O exemplo a seguir anexa manipuladores de eventos GotKeyboardFocus e LostKeyboardFocus 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 o 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 TextBox perde o foco do teclado, a propriedade Background do TextBox é retornada 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 encapsulamentos de eventos CLR. UIElement e ContentElement exporão esses eventos de forma mais conveniente.

Consulte também