Fokus - Übersicht

In WPF gibt es zwei Hauptkonzepte, bezüglich desFokus: Tastaturfokus und logischer Fokus. Tastaturfokus bezieht sich auf das Element, das Tastatureingaben empfängt, und der logische Fokus bezieht sich auf das Element in einem Fokusbereich, der Fokus besitzt. Diese Konzepte werden in dieser Übersicht ausführlich erläutert. Für das Erstellen von komplexen Anwendungen, die über mehrere Bereiche verfügen, in denen Fokus abgerufen werden kann, ist es wichtig den Unterschied der Konzepte zu verstehen.

Die wichtigsten Klassen, die an der Fokusverwaltung beteiligt sind, sind die Keyboard-Klasse, die FocusManager-Klasse, und die Basiselementklassen, wie z.B. UIElement und ContentElement. Weitere Informationen zu den Basiselementen finden Sie unter Übersicht über Basiselemente.

Die Keyboard-Klasse betrifft in erster Linie den Tastaturfokus und FocusManager den logischen Fokus, jedoch ist dies keine absolute Unterscheidung. Ein Element, das über den Tastaturfokus verfügt, besitzt auch einen logischen Fokus, aber ein Element mit dem logischen Fokus muss nicht unbedingt über den Tastaturfokus verfügen. Dies wird deutlich, wenn Sie mithilfe der Keyboard-Klasse das Element festlegen, das über den Tastaturfokus verfügt, da es auch den logischen Fokus auf das Element festlegt.

Tastaturfokus

Der Tastaturfokus bezieht sich auf das Element, das derzeit Tastatureingaben empfängt. Es kann nur ein Element auf dem gesamten Desktop geben, das über den Tastaturfokus verfügt. In WPF wird für das Element, das den Tastaturfokus besitzt, IsKeyboardFocused auf true festgelegt. Die statische Eigenschaft FocusedElement in der Keyboard-Klasse gibt das Element zurück, das aktuell den Tastaturfokus besitzt.

Damit ein Element den Tastaturfokus erhält, müssen die Focusable- und IsVisible-Eigenschaften auf true gesetzt sein. Bei einigen Klassen, z. B. der Basisklasse Panel, ist Focusable standardmäßig auf false festgelegt. Deshalb müssen Sie Focusable auf true setzen, wenn ein solches Element den Tastaturfokus erhalten soll.

Tastaturfokus kann durch die Interaktion mit der Benutzeroberfläche erhalten werden, z.B. durch das Wechseln mit der Tabulatortaste zu einem Element oder durch Klicken mit der Maus auf bestimmte Elemente. Der Tastaturfokus kann auch programmgesteuert mit der Focus-Methode der Keyboard-Klasse zugeteilt werden. Die Methode Focus versucht, dem angegebenen Element den Tastaturfokus zuzuteilen. Das zurückgegebene Element ist das Element mit Tastaturfokus, was möglicherweise ein anderes Element als angefordert sein kann, wenn das alte oder neue Fokusobjekt die Anforderung blockiert.

Im folgenden Beispiel wird die Methode Focus verwendet, um den Tastaturfokus auf ein Button-Element festzulegen.

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

Die Eigenschaft IsKeyboardFocused in den Basiselementklassen gibt einen Wert zurück, der angibt, ob das Element über den Tastaturfokus verfügt. Die Eigenschaft IsKeyboardFocusWithin in den Basiselementklassen gibt einen Wert zurück, der angibt, ob das Element oder eines seiner untergeordneten visuellen Elemente über den Tastaturfokus verfügt.

Wenn der anfängliche Fokus beim Start der Anwendung festgelegt wird, muss das Element, das den Fokus erhalten soll, in der visuellen Struktur des ersten von der Anwendung geladenen Fensters vorhanden sein, und für das Element muss Focusable und IsVisible auf true gesetzt sein. Es wird empfohlen, den anfänglichen Fokus im Loaded-Ereignishandler festzulegen. Es kann auch ein Dispatcher-Rückruf durch Aufrufen von Invoke oder BeginInvoke verwendet werden.

Logischer Fokus

Der logische Fokus bezieht ist das FocusManager.FocusedElement in einem Fokusbereich. Ein Fokusbereich ist ein Element, das innerhalb seines Bereichs das FocusedElement nachverfolgt. Wenn der Tastaturfokus einen Fokusbereich verlässt, wird das Element den Tastaturfokus verlieren, jedoch behält es den logischen Fokus. Wenn der Tastaturfokus zum Fokusbereich zurückkehrt, wird das Fokuselement Tastaturfokus erhalten. Somit kann der Tastaturfokus zwischen mehreren Fokusbereichen geändert werden, aber es wird sichergestellt, dass das Fokuselement im Fokusbereich erneut Tastaturfokus erhält, wenn der Fokus wieder zum Fokusbereich zurückkehrt.

Es können mehrere Elemente vorhanden sein, die über logischen Fokus in einer Anwendung verfügen, jedoch kann es nur ein Element geben, das den logischen Fokus in einem bestimmten Fokusbereich besitzt.

Ein Element, das den Tastaturfokus besitzt, verfügt über den logischen Fokus innerhalb des Fokusbereichs, dem er angehört.

Ein Element kann in Extensible Application Markup Language (XAML) in einen Fokusbereich umgewandelt werden, indem die an FocusManager angefügte Eigenschaft IsFocusScope auf true gesetzt wird. Im Code kann ein Element durch Aufrufen von SetIsFocusScope in einen Fokusbereich umgewandelt werden.

Das folgende Beispiel wandelt ein StackPanel-Element in einen Fokusbereich um, indem die angefügte IsFocusScope-Eigenschaft festgelegt wird.

<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 gibt den Fokusbereich für das angegebene Element zurück.

Klassen in WPF, die standardmäßig Fokusbereiche sind, sind Window, MenuItem, ToolBar und ContextMenu.

GetFocusedElement gibt das fokussierte Element des angegebenen Fokusbereichs zurück. SetFocusedElement legt das fokussierte Element im angegebenen Fokusbereichs fest. Mit SetFocusedElement wird üblicherweise das anfänglich fokussierte Element festgelegt.

Das folgende Beispiel legt das Fokuselement auf einen Fokusbereich fest und ruft das Fokuselement eines Fokusbereichs ab.

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

Tastaturnavigation

Die KeyboardNavigation-Klasse ist verantwortlich für das Implementieren der Standardtastaturfokusnavigation, wenn eine der Navigationstasten gedrückt wird. Die Navigationstasten sind: TAB, UMSCHALT+TAB, STRG+TAB, STRG+UMSCHALT+TAB, PFEIL-NACH-OBEN, PFEIL-NACH-UNTEN, PFEIL-NACH LINKS und PFEIL-NACH-RECHTS.

Das Navigationsverhalten eines Navigationscontainers kann geändert werden, indem die angefügten KeyboardNavigation-Eigenschaften TabNavigation, ControlTabNavigation und DirectionalNavigation festgelegt werden. Diese Eigenschaften sind vom Typ und KeyboardNavigationMode die möglichen Werte sind Continue, Local, Contained, Cycle, Once und None. Der Standardwert ist Continue, was bedeutet, dass das Element kein Navigationscontainer ist.

Im folgenden Beispiel wird ein Menu erstellt, die MenuItem-Objekte enthalten. Die angefügte Eigenschaft TabNavigation wird für das Menu auf Cycle gesetzt. Wenn der Fokus mit der Tab-Taste im Menu geändert wird, wird der Fokus aus jedem Element verschoben, und wenn das letzte Element erreicht ist, wird der Fokus zum ersten Element zurückkehren.

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

Zusätzliche APIs für die Arbeit mit dem Fokus sind MoveFocus und PredictFocus.

MoveFocus ändert den Fokus auf das nächste Element in der Anwendung. Ein TraversalRequest wird verwendet, um die Richtung anzugeben. Die an MoveFocus übergebene FocusNavigationDirection legt die verschiedenen Richtungen fest, in die der Fokus verschoben werden kann, z. B. First, Last, Up und Down.

Im folgenden Beispiel wird der MoveFocus verwendet, um das fokussierte Element zu ändern.

// 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 gibt das Objekt zurück, was den Fokus erhalten würde, wenn der Fokus geändert werden würde. Derzeit werden nur Up, Down, Left und Right von PredictFocus unterstützt.

Fokusereignisse

Die Ereignisse im Zusammenhang mit dem Tastaturfokus sind PreviewGotKeyboardFocus, GotKeyboardFocus, PreviewLostKeyboardFocus und LostKeyboardFocus. Die Ereignisse werden als angefügte Ereignisse in der Keyboard-Klasse definiert, sind aber als entsprechende Routingereignissen in Basiselementklassen sofort zugänglich. Weitere Informationen zu Ereignissen finden Sie unter Übersicht über Routingereignisse.

GotKeyboardFocus wird ausgelöst, wenn das Element den Tastaturfokus erhält. LostKeyboardFocus wird ausgelöst, wenn das Element den Tastaturfokus verliert. Wenn das Ereignis PreviewGotKeyboardFocus oder das Ereignis PreviewLostKeyboardFocusEvent behandelt und Handled auf true gesetzt ist, ändert sich der Fokus nicht.

Im folgenden Beispiel werden die Ereignishandler GotKeyboardFocus und LostKeyboardFocus an eine TextBox angfügt.

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

Wenn die TextBox den Tastaturfokus erhält, wird die Background-Eigenschaft der TextBox zu LightBlue geändert.

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

Wenn die TextBox den Tastaturfokus verliert, wird die Background-Eigenschaft der TextBox wieder zu Weiß geändert.

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

Die Ereignisse im Zusammenhang mit dem logischen Fokus sind GotFocus und LostFocus. Diese Ereignisse werden im FocusManager als angefügte Ereignisse definiert, aber FocusManager stellt keine CLR-Ereigniswrapper zur Verfügung. UIElement und ContentElement stellen diese Ereignisse auf einfachere Weise zur Verfügung.

Weitere Informationen