Condividi tramite


Panoramica del focus

In WPF ci sono due concetti principali che riguardano il focus: il focus della tastiera e il focus logico. Lo stato attivo della tastiera si riferisce all'elemento che riceve l'input della tastiera, e lo stato attivo logico si riferisce all'elemento in un ambito di messa a fuoco che ha lo stato attivo. Questi concetti vengono illustrati in dettaglio in questa panoramica. Comprendere la differenza tra questi concetti è importante per la creazione di applicazioni complesse con più aree in cui è possibile concentrare l'attenzione.

Le classi principali che partecipano alla gestione dello stato attivo sono la classe Keyboard, la classe FocusManager e le classi degli elementi di base, come UIElement e ContentElement. Per altre informazioni sugli elementi di base, vedere cenni preliminari sugli elementi di base .

La classe Keyboard riguarda principalmente il focus della tastiera e la FocusManager principalmente il focus logico, ma questa non è una distinzione assoluta. Un elemento con lo stato attivo della tastiera avrà anche lo stato attivo logico, ma un elemento con stato attivo logico non ha necessariamente lo stato attivo della tastiera. Questo è evidente quando si usa la classe Keyboard per impostare l'elemento con lo stato attivo della tastiera, poiché questo imposta anche lo stato attivo logico sull'elemento.

Focus della tastiera

Il fuoco della tastiera si riferisce all'elemento che attualmente riceve l'input da tastiera. Solo un elemento su tutto il desktop può avere il focus della tastiera. In WPF, l'elemento con stato attivo della tastiera avrà IsKeyboardFocused impostato su true. La proprietà statica FocusedElement della classe Keyboard ottiene l'elemento che attualmente ha il focus della tastiera.

Affinché un elemento ottenga lo stato attivo della tastiera, le proprietà Focusable e IsVisible sugli elementi base devono essere impostate su true. Alcune classi, come la classe base Panel, hanno Focusable impostato su false per impostazione predefinita; quindi, è necessario impostare Focusable su true se si desidera che tale elemento possa ottenere il focus della tastiera.

Lo stato attivo della tastiera può essere ottenuto tramite l'interazione dell'utente con l'interfaccia utente, ad esempio passando con il tasto Tab da un elemento all'altro o cliccando su determinati elementi. Lo stato attivo della tastiera può essere ottenuto anche programmaticamente usando il metodo Focus nella classe Keyboard. Il metodo Focus tenta di assegnare lo stato attivo della tastiera all'elemento specificato. L'elemento restituito è l'elemento con stato attivo della tastiera, che potrebbe essere un elemento diverso da quello richiesto se l'oggetto attivo precedente o nuovo blocca la richiesta.

Nell'esempio seguente viene utilizzato il metodo Focus per impostare il focus su un 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

La proprietà IsKeyboardFocused nelle classi di elementi di base restituisce un valore che indica se l'elemento ha il focus della tastiera. La proprietà IsKeyboardFocusWithin nelle classi di elementi di base riporta un valore che indica se l'elemento o uno dei relativi elementi figlio visivi ha lo stato attivo della tastiera.

Quando si imposta il fuoco iniziale all'avvio dell'applicazione, l'elemento che deve ricevere il fuoco deve trovarsi nell'albero visivo della finestra iniziale caricata dall'applicazione e deve avere Focusable e IsVisible impostati su true. La posizione consigliata per impostare lo stato attivo iniziale si trova nel gestore eventi Loaded. È anche possibile usare un callback Dispatcher chiamando Invoke o BeginInvoke.

Fuoco logico

Lo stato attivo logico fa riferimento al FocusManager.FocusedElement in un ambito dello stato attivo. Un ambito di messa a fuoco è un elemento che tiene traccia del FocusedElement all'interno del suo ambito. Quando il fuoco della tastiera esce da un'area di fuoco, l'elemento focalizzato perde il fuoco della tastiera ma mantiene il fuoco logico. Quando lo stato attivo della tastiera ritorna all'ambito di stato attivo, l'elemento focalizzato riceverà lo stato attivo della tastiera. Ciò consente di modificare il focus della tastiera tra diversi ambiti, ma garantisce che l'elemento con focus all'interno di un ambito riacquisti il focus quando questo torna all'ambito di origine.

In un'applicazione possono essere presenti più elementi con stato attivo logico, ma può essere presente un solo elemento con stato attivo logico in un determinato ambito dello stato attivo.

Un elemento che ha il focus della tastiera ha il focus logico per l'ambito a cui appartiene.

Un elemento può essere trasformato in un ambito di messa a fuoco in XAML (Extensible Application Markup Language) impostando la proprietà associata FocusManagerIsFocusScope su true. Nel codice, un elemento può essere trasformato in un ambito di messa a fuoco chiamando SetIsFocusScope.

L'esempio seguente trasforma un StackPanel in un ambito di messa a fuoco impostando la proprietà associata 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 restituisce l'ambito di messa a fuoco per l'elemento specificato.

Le classi in WPF che sono ambiti di focalizzazione per impostazione predefinita sono Window, MenuItem, ToolBare ContextMenu.

GetFocusedElement ottiene l'elemento a cui è attribuito lo stato attivo per l'ambito dello stato attivo specificato. SetFocusedElement imposta l'elemento focalizzato nell'ambito di messa a fuoco specificato. SetFocusedElement viene in genere usato per impostare l'elemento focalizzato iniziale.

L'esempio seguente imposta l'elemento con stato attivo in un ambito di messa a fuoco e ottiene l'elemento focalizzato di un ambito di messa a fuoco.

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

Spostamento tramite tastiera

La classe KeyboardNavigation è responsabile dell'implementazione della navigazione di messa a fuoco predefinita della tastiera quando viene premuto uno dei tasti di navigazione. I tasti di spostamento sono TAB, MAIUSC+TAB, CTRL+TAB, CTRL+MAIUSC+TAB, UPARROW, DOWNARROW, LEFTARROW e RIGHTARROW.

Il comportamento di navigazione di un contenitore per la navigazione può essere modificato impostando le proprietà KeyboardNavigation associati TabNavigation, ControlTabNavigatione DirectionalNavigation. Queste proprietà sono di tipo KeyboardNavigationMode e i valori possibili sono Continue, Local, Contained, Cycle, Oncee None. Il valore predefinito è Continue, il che significa che l'elemento non è un contenitore di navigazione.

Nell'esempio seguente viene creato un Menu con un certo numero di oggetti MenuItem. La proprietà associata TabNavigation è impostata su Cycle nel Menu. Quando lo stato attivo viene modificato usando il tasto TAB all'interno del Menu, lo stato attivo si sposta da ogni elemento e quando l'ultimo elemento viene raggiunto lo stato attivo tornerà al primo 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)

L'API aggiuntiva da usare con il focus sono MoveFocus e PredictFocus.

MoveFocus cambia il focus sull'elemento successivo nell’app. Viene utilizzato un TraversalRequest per specificare la direzione. Il FocusNavigationDirection passato a MoveFocus specifica le diverse direzioni in cui lo stato attivo può essere spostato, come First, Last, Up e Down.

L'esempio seguente usa MoveFocus per modificare l'elemento con stato attivo.

// 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 restituisce l'oggetto che riceverebbe lo stato attivo qualora lo stato attivo venisse modificato. Attualmente, solo Up, Down, Lefte Right sono supportati da PredictFocus.

Eventi di focalizzazione

Gli eventi relativi alla messa a fuoco della tastiera sono PreviewGotKeyboardFocus, GotKeyboardFocus e PreviewLostKeyboardFocus, LostKeyboardFocus. Gli eventi vengono definiti come eventi associati nella classe Keyboard, ma sono più facilmente accessibili come eventi indirizzati equivalenti nelle classi di elementi di base. Per altre informazioni sugli eventi, vedere la panoramica degli eventi indirizzati .

GotKeyboardFocus viene generato quando l'elemento ottiene lo stato attivo della tastiera. LostKeyboardFocus viene generato quando l'elemento perde lo stato attivo della tastiera. Se l'evento PreviewGotKeyboardFocus o l'evento PreviewLostKeyboardFocusEvent è gestito e Handled è impostato su true, allora il focus non cambierà.

Nell'esempio seguente, i gestori degli eventi GotKeyboardFocus e LostKeyboardFocus vengono associati a un 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 il TextBox ottiene lo stato attivo della tastiera, la proprietà Background del TextBox viene modificata in 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 il TextBox perde il focus della tastiera, la proprietà Background del TextBox viene modificata nuovamente in bianco.

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

Gli eventi correlati allo stato attivo logico sono GotFocus e LostFocus. Questi eventi sono definiti nella FocusManager come eventi allegati, ma FocusManager non espone i wrapper degli eventi CLR. UIElement e ContentElement offrono questi eventi più comodamente.

Vedere anche