Fókusz áttekintése

A WPF-ben két fő fogalma van a fókusznak: a billentyűzetfókusz és a logikai fókusz. A billentyűzetfókusz arra az elemre vonatkozik, amely a billentyűzetbemenetet fogadja, a logikai fókusz pedig a fókuszt tartalmazó fókusz hatókörének elemére vonatkozik. Ezeket a fogalmakat részletesen tárgyaljuk ebben az áttekintésben. Ezeknek a fogalmaknak a különbségének megértése fontos az olyan összetett alkalmazások létrehozásához, amelyek több régióval rendelkeznek, ahol a fókusz elérhető.

A fókuszkezelésben részt vevő fő osztályok a Keyboard osztály, a FocusManager osztály és az alapelemosztályok, például UIElement és ContentElement. További információ az alapelemekről: Alapelemek áttekintése.

A Keyboard osztály elsősorban a billentyűzetfókuszsal foglalkozik, a FocusManager pedig elsősorban a logikai fókuszsal foglalkozik, de ez nem abszolút különbség. A billentyűzetfókuszú elemek is logikai fókuszban lesznek, de a logikai fókuszú elemek nem feltétlenül rendelkeznek billentyűzetfókusszal. Ez akkor válik nyilvánvalóvá, ha a Keyboard osztályt használja a billentyűzetfókuszú elem beállításához, mert az logikai fókuszt is beállít az elemre.

Billentyűzetfókusz

A billentyűzetfókusz arra az elemre vonatkozik, amely jelenleg billentyűzetbemenetet fogad. A billentyűzetfókuszt tartalmazó asztalon csak egy elem lehet. A WPF-ben a billentyűzetfókuszú elem IsKeyboardFocusedtruelesz beállítva. A FocusedElement osztály statikus tulajdonsága Keyboard az aktuális billentyűzetfókuszú elemet kapja.

Ahhoz, hogy egy elem megkapja a billentyűzetfókuszt, az alapelemek Focusable és IsVisible tulajdonságait truekell beállítani. Egyes osztályok, például az Panel alaposztály, alapértelmezés szerint a Focusablefalse-re van állítva; ezért Focusable kell beállítania true, ha azt szeretné, hogy egy ilyen elem képes legyen a fókusz elérésére a billentyűzettel.

A billentyűzetfókusz a felhasználói felülettel való felhasználói interakcióval érhető el, például egy elemhez való lapozással vagy bizonyos elemeken az egérre való kattintással. A billentyűzetfókusz programozott módon is elérhető a Focus osztály Keyboard metódusával. A Focus metódus megpróbálja fókuszba helyezni a megadott elem billentyűzetét. A visszaadott elem a billentyűzetfókuszú elem, amely a kéréstől eltérő elem lehet, ha a régi vagy az új fókuszobjektum blokkolja a kérést.

Az alábbi példa a Focus metódust használja egy Buttonbillentyűzetfókuszának beállításához.

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

Az alapelemosztályok IsKeyboardFocused tulajdonsága egy értéket kap, amely jelzi, hogy az elem rendelkezik-e billentyűzetfókuszsal. Az alapelemosztályok IsKeyboardFocusWithin tulajdonsága olyan értéket kap, amely jelzi, hogy az elem vagy annak bármely vizuális gyermekeleme rendelkezik-e billentyűzetfókuszsal.

Amikor az alkalmazás indításakor beállítjuk a kezdeti fókuszt, a fókuszt kapó elemnek az alkalmazás által betöltött kezdeti ablak vizuális fájában kell lennie, és az elemnél a Focusable és IsVisible értékének true-nek kell lennie. A kezdeti fókusz beállításának ajánlott helye az Loaded eseménykezelőben található. A Dispatcher visszahívás Invoke vagy BeginInvokehívásával is használható.

Logikai fókusz

A logikai fókusz a fókusz hatókörében a FocusManager.FocusedElement-ra utal. A fókusz tartomány olyan elem, amely nyomon követi a saját hatókörén belüli FocusedElement-t. Ha a billentyűzetfókusz elhagyja a fókusz hatókörét, a szűrt elem elveszíti a billentyűzetfókuszt, de megtartja a logikai fókuszt. Amikor a billentyűzetfókusz visszakerül a fókusz hatókörébe, a szűrt elem megkapja a billentyűzetfókuszt. Ez lehetővé teszi, hogy a billentyűzet fókusza több fókusztartomány között megváltozzon, de biztosítja, hogy a fókusz hatókörének szűrt eleme visszanyerje a billentyűzet fókuszát, amikor a fókusz visszakerül a fókusz hatókörébe.

Több olyan elem is lehet, amelynek logikai fókusza van egy alkalmazásban, de lehet, hogy csak egy elem rendelkezik logikai fókuszsal egy adott fókusztartományban.

A billentyűzetfókuszú elem logikai fókuszt használ arra a fókusztartományra, amelyhez tartozik.

Egy elem az Extensible Application Markup Language (XAML) alkalmazásban fókusz körré alakítható, ha a FocusManager csatolt tulajdonságot IsFocusScopetrueértékre állítják. A kódban az elemek fókusztartománysá alakíthatók SetIsFocusScopemeghívásával.

Az alábbi példa a StackPanel elemet fókuszterületté alakítja a IsFocusScope csatolt tulajdonság beállításával.

<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 a megadott elem fókusztartományát adja vissza.

A WPF-ben alapértelmezés szerint fókuszhatókörként szolgáló osztályok Window, MenuItem, ToolBarés ContextMenu.

GetFocusedElement lekéri a megadott fókusztartomány szűrt elemét. SetFocusedElement beállítja a szűrt elemet a megadott fókusztartományban. SetFocusedElement általában a kezdeti fókuszált elem beállítására használnak.

Az alábbi példa beállítja a fókusz hatókörének szűrt elemét, és lekéri a fókusz hatókörének szűrt elemét.

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

Billentyűzet-navigáció

Az KeyboardNavigation osztály felelős az alapértelmezett billentyűzetfókusz-navigáció megvalósításáért, amikor az egyik navigációs gombot lenyomja. A navigációs kulcsok a következők: TAB, SHIFT+TAB, CTRL+TAB, CTRL+SHIFT+TAB, UPARROW, DOWNARROW, LEFTARROW és RIGHTARROW billentyűk.

A navigációs tárolók navigációs viselkedése a csatolt KeyboardNavigation tulajdonságok TabNavigation, ControlTabNavigationés DirectionalNavigationbeállításával módosítható. Ezek a tulajdonságok KeyboardNavigationMode típusúak, és a lehetséges értékek a következők: Continue, Local, Contained, Cycle, Onceés None. Az alapértelmezett érték Continue, ami azt jelenti, hogy az elem nem navigációs tároló.

A következő példa egy Menu-t hoz létre több MenuItem objektummal. A TabNavigation csatolt tulajdonság a Cycle-n Menu-re van állítva. Ha a fókusz a Menubelüli tabulátorbillentyűvel változik, a fókusz minden elemről elmozdul, és az utolsó elem elérésekor a fókusz visszakerül az első elemre.

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

A fókusz kezeléséhez további API-k állnak rendelkezésre: MoveFocus és PredictFocus.

MoveFocus az alkalmazás következő elemére helyezi a fókuszt. A TraversalRequest az irány megadására szolgál. A FocusNavigationDirection, amelyet átadunk a MoveFocus-nak, meghatározza, hogy milyen irányba mozdítható a fókusz, például First, Last, Up és Down.

Az alábbi példa a MoveFocus-t használja a fókuszált elem módosításához.

// 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 visszaadja azt az objektumot, amely fókuszt kap a fókusz módosítása esetén. Jelenleg a Upcsak a Down, Left, Rightés PredictFocus típusokat támogatja.

Fókuszesemények

A billentyűzetfókuszhoz kapcsolódó események a következők: PreviewGotKeyboardFocus, GotKeyboardFocus és PreviewLostKeyboardFocus, LostKeyboardFocus. Az események csatolt eseményként vannak definiálva az Keyboard osztályban, de könnyebben elérhetők az alapelemosztályok egyenértékű irányított eseményeiként. További információért az eseményekről lásd: Irányított események áttekintése.

GotKeyboardFocus akkor merül fel, amikor az elem megkapja a billentyűzetfókuszt. LostKeyboardFocus akkor merül fel, ha az elem elveszíti a billentyűzetfókuszt. Ha a PreviewGotKeyboardFocus vagy a PreviewLostKeyboardFocusEvent eseményt kezelik, és a Handled-t true-ra állítják be, akkor a fókusz nem változik.

Az alábbi példa GotKeyboardFocus- és LostKeyboardFocus-eseménykezelőket csatol a TextBox-höz.

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

Amikor a TextBox megkapja a billentyűzetfókuszt, a BackgroundTextBox tulajdonsága LightBluelesz.

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

Amikor a TextBox elveszíti a billentyűzetfókuszt, a BackgroundTextBox tulajdonsága visszaáll fehérre.

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

A logikai fókuszhoz kapcsolódó események GotFocus és LostFocus. Ezek az események csatolt eseményként vannak definiálva a FocusManager, de a FocusManager nem teszi elérhetővé a CLR-eseményburkolókat. UIElement és ContentElement kényelmesebben teszik elérhetővé ezeket az eseményeket.

Lásd még