Visão geral do foco

No WPF existem dois conceitos principais que dizem respeito ao foco: foco no teclado e foco lógico. O foco do teclado refere-se ao elemento que recebe entrada do teclado e foco lógico refere-se ao elemento em um escopo de foco que tem foco. Esses conceitos são discutidos em detalhes nesta visão geral. Noções básicas sobre a diferença entre esses conceitos é importante para a criação de aplicativos complexos que têm várias regiões no qual o foco pode ser obtido.

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

A Keyboard classe está preocupada principalmente com o foco do teclado e a está preocupada principalmente com o FocusManager foco lógico, mas esta não é uma distinção absoluta. Um elemento que tem o foco do teclado também terá foco lógico, mas não necessariamente um elemento que tenha foco lógico tem o foco do teclado. Isso é aparente 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 atualmente entrada do teclado. Em toda a área de trabalho, pode haver apenas um elemento que tem o foco do teclado. No WPF, o elemento que tem o foco do teclado terá IsKeyboardFocused definido como true. A propriedade FocusedElement static na classe obtém o Keyboard elemento que atualmente tem foco de teclado.

Para que um elemento obtenha o foco do teclado, as Focusable propriedades e nos IsVisible elementos base devem ser definidas como true. Algumas classes, como a Panel classe base, foram Focusable definidas como false por padrão, portanto, você deve definir Focusable como true se quiser que tal elemento seja capaz de 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 tabulação de um elemento ou clicar com o mouse em determinados elementos. O foco do teclado também pode ser obtido programaticamente usando o FocusKeyboard método na classe. O Focus método tenta dar foco ao teclado do elemento especificado. O elemento retornado é o elemento que tem o foco do teclado, que pode ser um elemento diferente do solicitado se o velho ou o novo objeto de foco bloquear a solicitação.

O exemplo a seguir usa o método para definir o foco do Focus teclado em um Buttonarquivo .

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 foco no teclado. A IsKeyboardFocusWithin propriedade nas classes de elemento base obtém um valor que indica se o elemento ou qualquer um de seus elementos filho visuais tem foco no teclado.

Ao definir o foco inicial na inicialização do aplicativo, o elemento a ser recebido 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 é no manipulador de Loaded eventos. Um Dispatcher retorno de chamada também pode ser usado chamando Invoke ou BeginInvoke.

Foco lógico

Foco lógico refere-se ao FocusManager.FocusedElement escopo em um foco. Um escopo de foco é um elemento que mantém o FocusedElement controle dentro de seu escopo. Quando o foco de teclado deixar um escopo de foco, o elemento com foco perderá o foco do teclado mas manterá o foco lógico. Quando o foco de teclado retornar para o 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 assegura que o elemento focalizado no escopo de foco recupere o foco do teclado quando o foco retornar para o escopo de foco.

Pode haver vários elementos que têm foco lógico em um aplicativo, mas pode haver apenas um elemento com 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 a que pertence.

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

O exemplo a seguir transforma um em um StackPanel escopo de foco definindo a IsFocusScope propriedade 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, , MenuItemToolBare ContextMenu.

GetFocusedElement Obtém o elemento Focused para o escopo de foco especificado. SetFocusedElement Define o elemento Focused no escopo de foco especificado. SetFocusedElement é normalmente usado para definir o elemento de foco inicial.

O exemplo a seguir define o elemento focalizado 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 teclas de navegação são: TAB, SHIFT + TAB, CTRL + TAB, CTRL + SHIFT + TAB, setas para cima, para baixo, esquerda e direita.

O comportamento de navegação de um contêiner de navegação pode ser alterado definindo as propriedades TabNavigationanexadas KeyboardNavigation , ControlTabNavigatione DirectionalNavigation. Essas propriedades são do tipo KeyboardNavigationMode e os valores possíveis são Continue, , , CycleLocalContained, Oncee .None O valor padrão é , o que significa que o elemento não é Continueum contêiner de navegação.

O exemplo a seguir cria um Menu com vários MenuItem objetos. A TabNavigation propriedade anexada Menué definida como Cycle no . Quando o foco é alterado usando a tecla tab dentro do , o foco se move de cada elemento e, quando o último elemento é atingido, o Menufoco 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 adicionais para trabalhar com foco são MoveFocus e PredictFocus.

MoveFocus Altera o foco para o próximo elemento no aplicativo. A TraversalRequest é usado para especificar a direção. O FocusNavigationDirection passado para MoveFocus especifica as direções diferentes que o foco pode ser movido, como First, UpLaste Down.

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

// 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, , , DownLefte Right são suportados pelo 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 Keyboard na classe, mas são mais facilmente acessíveis como eventos roteados equivalentes nas classes de elemento base. Para obter mais informações sobre os 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 ou o evento for manipulado e Handled estiver definido como true, o PreviewGotKeyboardFocusPreviewLostKeyboardFocusEvent foco não será alterado.

O exemplo a seguir anexa e LostKeyboardFocus manipula GotKeyboardFocus eventos a um TextBoxarquivo .

<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 obtém o TextBox foco do teclado, a Background propriedade 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 perde o foco do TextBox teclado, a Background propriedade do é alterada de TextBox 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 wrappers de eventos CLR. UIElement e ContentElement expor esses eventos de forma mais conveniente.

Confira também