Sdílet prostřednictvím


Přehled zaměření

Ve WPF existují dva hlavní koncepty, které se týkají fokusu: fokus klávesnice a logický fokus. Fokus klávesnice odkazuje na prvek, který přijímá vstup klávesnice a logický fokus odkazuje na prvek v oboru fokusu, který má fokus. Tyto koncepty jsou podrobně popsány v tomto přehledu. Pochopení rozdílu v těchto konceptech je důležité pro vytváření složitých aplikací, které mají více oblastí, kde je možné získat zaměření.

Hlavní třídy, které se účastní správy fokusu, jsou třída Keyboard, třída FocusManager a základní prvkové třídy, jako jsou UIElement a ContentElement. Další informace o základních elementech naleznete v Přehled základních prvků.

Třída Keyboard se zabývá především fokusem klávesnice a FocusManager se zabývá především logickým fokusem, ale nejedná se o absolutní rozlišení. Prvek s fokusem klávesnice bude mít také logický fokus, ale prvek, který má logický fokus, nemusí mít fokus klávesnice. Je to zřejmé, když použijete třídu Keyboard k nastavení prvku, který má zaměření klávesnice, neboť také nastaví logické zaměření na prvek.

Fokus klávesnice

Fokus klávesnice odkazuje na prvek, který aktuálně přijímá vstup klávesnice. Na celé ploše může být jenom jeden prvek, který má zaměření pomocí klávesnice. Ve WPF bude prvek s fokusem klávesnice mít IsKeyboardFocused nastaven na true. Statická vlastnost FocusedElement ve třídě Keyboard získá prvek, který má aktuálně fokus klávesnice.

Aby prvek získal fokus klávesnice, musí být vlastnosti Focusable a IsVisible základních prvků nastaveny na true. Některé třídy, například základní třída Panel, mají Focusable ve výchozím nastavení nastaveny na false; proto je nutné nastavit Focusable na true, pokud chcete, aby takový prvek mohl získat fokus klávesnice.

Fokus klávesnice lze získat prostřednictvím interakce uživatele s uživatelským rozhraním, například přechodem na prvek pomocí klávesy Tab nebo kliknutím myši na určité prvky. Fokus klávesnice lze také získat programově pomocí metody Focus ve třídě Keyboard. Metoda Focus se pokusí přiřadit zadanému prvku klávesový fokus. Vrácený prvek je prvek, který má fokus klávesnice, což může být jiný prvek než požadovaný, pokud starý nebo nový objekt fokusu zablokuje požadavek.

Následující příklad používá metodu Focus k nastavení fokusu klávesnice na 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

Vlastnost IsKeyboardFocused třídy základních elementů získá hodnotu určující, zda prvek má fokus klávesnice. Vlastnost IsKeyboardFocusWithin třídy základních elementů získá hodnotu určující, zda prvek nebo některý z jeho vizuálních podřízených prvků má fokus klávesnice.

Při nastavování počátečního fokusu při spuštění aplikace musí být prvek pro příjem fokusu ve vizuálním stromu počátečního okna načteného aplikací a prvek musí mít Focusable a IsVisible nastaven na true. Doporučené místo pro nastavení počátečního fokusu je v obslužné rutině události Loaded. Zpětné volání Dispatcher lze použít také voláním Invoke nebo BeginInvoke.

Logický fokus

Logický fokus odkazuje na FocusManager.FocusedElement v oboru fokusu. Rozsah fokusu je prvek, který sleduje prvek FocusedElement v rámci svého dosahu. Když fokus klávesnice opustí obor zaměření, fokusovaný prvek ztratí fokus klávesnice, ale zachová si logické zaostření. Když se zaostření klávesnice vrátí do oblasti zaostření, zaostřený prvek získá zaostření klávesnice. To umožňuje změnit zaostření klávesnice mezi více oblastmi zaostření, ale zajistí, aby zaostřený prvek v oblasti zaostření znovu získal zaostření klávesnice, když se zaostření vrátí zpět do této oblasti.

V aplikaci může existovat více prvků, které mají logický fokus, ale může existovat pouze jeden prvek, který má logický fokus v konkrétním oboru fokusu.

Prvek s fokusem klávesnice má logický fokus pro rozsah fokusu, do kterého patří.

Prvek lze v jazyce XAML (Extensible Application Markup Language) převést na rozsah fokusu nastavením připojené vlastnosti FocusManagerIsFocusScope na true. V kódu lze prvek převést na rozsah zaměření voláním SetIsFocusScope.

Následující příklad přemění StackPanel na obor fokusu nastavením připojené vlastnosti 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 vrátí rozsah fokusu pro zadaný prvek.

Třídy ve WPF, které jsou ve výchozím nastavení rozsahy fokusu, jsou Window, MenuItem, ToolBara ContextMenu.

GetFocusedElement získá zaostřený prvek pro zadaný rozsah fokusu. SetFocusedElement nastaví prioritní prvek v zadaném oboru fokusu. SetFocusedElement se obvykle používá k nastavení počátečního prioritního prvku.

Následující příklad nastaví fokusovaný prvek na fokusový obor a získá fokusovaný prvek z fokusového oboru.

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

Navigace pomocí klávesnice

Třída KeyboardNavigation zodpovídá za implementaci výchozí navigace fokusu klávesnice při stisknutí některé z navigačních kláves. Navigační klávesy jsou: TAB, SHIFT+TAB, CTRL+TAB, CTRL+SHIFT+TAB, UPARROW, DOWNARROW, LEFTARROW a RIGHTARROW.

Chování navigace v navigačním kontejneru lze změnit nastavením připojených vlastností KeyboardNavigationTabNavigation, ControlTabNavigationa DirectionalNavigation. Tyto vlastnosti jsou typu KeyboardNavigationMode a možné hodnoty jsou Continue, Local, Contained, Cycle, Oncea None. Výchozí hodnota je Continue, což znamená, že prvek není navigační kontejner.

Následující příklad vytvoří Menu s několika MenuItem objekty. Připojená vlastnost TabNavigation je v Menunastavena na Cycle. Při změně fokusu pomocí klávesy Tab v rámci Menuse fokus přesune z každého prvku a když se dosáhne posledního prvku, vrátí se k prvnímu prvku.

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

Další rozhraní API pro práci s fokusem jsou MoveFocus a PredictFocus.

MoveFocus posune pozornost na další prvek aplikace. K určení směru se používá TraversalRequest. FocusNavigationDirection předaný MoveFocus určuje různé směry, ve kterých lze posunout zaostření, jako například First, Last, Up a Down.

Následující příklad používá MoveFocus ke změně prioritního prvku.

// 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 vrátí objekt, který by při změně fokusu získal fokus. V současné době jsou Up, Down, Lefta Right podporovány systémem PredictFocus.

Události fokusu

Události související s fokusem klávesnice jsou PreviewGotKeyboardFocus, GotKeyboardFocus a PreviewLostKeyboardFocus, LostKeyboardFocus. Události jsou definovány jako připojené události ve třídě Keyboard, ale jsou lépe dostupné jako ekvivalentní směrované události v základních třídách elementů. Další informace o událostech naleznete v části Přehled směrovaných událostí.

GotKeyboardFocus se vyvolá, když prvek získá fokus klávesnice. LostKeyboardFocus se vyvolá, když prvek ztratí fokus klávesnice. Pokud je událost PreviewGotKeyboardFocus nebo PreviewLostKeyboardFocusEvent zpracována a Handled je nastaveno na true, zaostření se nezmění.

Následující příklad připojí obslužné rutiny událostí GotKeyboardFocus a LostKeyboardFocus k objektu 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>

Když TextBox získá fokus klávesnice, změní se vlastnost Background u TextBox na 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

Když TextBox ztratí klávesnicový fokus, vlastnost Background objektu TextBox se změní zpět na bílou.

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

Události související s logickým fokusem jsou GotFocus a LostFocus. Tyto události jsou definovány v FocusManager jako připojené události, ale FocusManager nezpřístupňuje obálky událostí CLR. UIElement a ContentElement tyto události zpřístupňují pohodlněji.

Viz také