Cenni preliminari sullo stato attivo

In WPF sono disponibili due concetti principali relativi allo stato attivo: lo stato attivo della tastiera e lo stato attivo logico. Lo stato attivo della tastiera fa riferimento all'elemento che riceve l'input della tastiera, mentre lo stato attivo logico fa riferimento all'elemento di un ambito che ha ricevuto lo stato attivo. In questa panoramica verranno illustrati in dettaglio questi concetti. Comprendere le differenze esistenti tra questi concetti è fondamentale per la creazione di applicazioni complesse costituite da più aree in cui è possibile ottenere lo stato attivo.

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

La Keyboard classe riguarda principalmente lo stato attivo della tastiera e si FocusManager occupa principalmente dello stato attivo logico, ma questa non è una distinzione assoluta. Un elemento con lo stato attivo della tastiera presenta anche lo stato attivo logico, mentre un elemento che ha ottenuto lo stato attivo logico non ha necessariamente lo stato attivo della tastiera. Questo è evidente quando si usa la Keyboard classe per impostare l'elemento con lo stato attivo della tastiera, perché imposta anche lo stato attivo logico sull'elemento.

Stato attivo della tastiera

Lo stato attivo della tastiera fa riferimento all'elemento che riceve l'input dalla tastiera. Su un desktop può esserci un solo elemento con lo stato attivo della tastiera. In WPF l'elemento con lo stato attivo della tastiera sarà IsKeyboardFocused impostato su true. La proprietà FocusedElement statica della Keyboard classe ottiene l'elemento che ha attualmente lo stato attivo della tastiera.

Affinché un elemento ottenga lo stato attivo della tastiera, le Focusable proprietà e IsVisible sugli elementi di base devono essere impostate su true. Alcune classi, ad esempio la Panel classe base, sono Focusable impostate su false per impostazione predefinita. Pertanto, è necessario impostare su Focusabletrue se si desidera che tale elemento sia in grado di ottenere lo stato attivo della tastiera.

Lo stato attivo della tastiera può essere ottenuto tramite l'interazione dell'utente con l'interfaccia utente, ad esempio tabulazione su un elemento o facendo clic sul mouse su determinati elementi. Lo stato attivo della tastiera può anche essere ottenuto a livello di codice usando il Focus metodo sulla Keyboard classe . Il Focus metodo tenta di assegnare lo stato attivo alla tastiera dell'elemento specificato. L'elemento restituito è l'elemento con lo stato attivo della tastiera e potrebbe non essere quello richiesto se l'oggetto stato attivo nuovo o quello precedente blocca la richiesta.

Nell'esempio seguente viene utilizzato il metodo per impostare lo Focus stato attivo della tastiera su un oggetto 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 IsKeyboardFocused proprietà sulle classi di elementi di base ottiene un valore che indica se l'elemento ha lo stato attivo della tastiera. La IsKeyboardFocusWithin proprietà sulle classi di elementi di base ottiene un valore che indica se l'elemento o uno dei relativi elementi figlio visivi ha lo stato attivo della tastiera.

Quando si imposta lo stato attivo iniziale all'avvio dell'applicazione, l'elemento per ricevere lo stato attivo deve trovarsi nella struttura ad albero visuale della finestra iniziale caricata dall'applicazione e l'elemento deve avere Focusable e IsVisible impostare su true. La posizione consigliata per impostare lo Loaded stato attivo iniziale si trova nel gestore eventi. Un Dispatcher callback può essere usato anche chiamando Invoke o BeginInvoke.

Stato attivo logico

Lo stato attivo logico fa riferimento a FocusManager.FocusedElement in un ambito dello stato attivo. Un ambito dello stato attivo è un elemento che tiene traccia dell'oggetto all'interno dell'ambito FocusedElement . Quando lo stato attivo della tastiera lascia un ambito di stato attivo, l'elemento con lo stato attivo perde lo stato attivo della tastiera, ma mantiene quello logico. Quando lo stato attivo della tastiera torna nell'ambito di stato attivo, l'elemento con lo stato attivo ottiene lo stato attivo della tastiera. In questo modo, lo stato attivo della tastiera può essere passato tra più ambiti, ma l'elemento con lo stato attivo nell'ambito di stato attivo ottiene sicuramente di nuovo lo stato attivo della tastiera quando lo stato attivo ritorna all'ambito di stato attivo.

In un'applicazione possono esserci più elementi con lo stato attivo logico, ma in un determinato ambito di stato attivo può esserci un solo elemento con lo stato attivo logico.

Un elemento con stato attivo della tastiera ha lo stato attivo logico per l'ambito a cui appartiene.

Un elemento può essere trasformato in un ambito di stato attivo in XAML (Extensible Application Markup Language) impostando la FocusManager proprietà IsFocusScope associata su true. Nel codice, un elemento può essere trasformato in un ambito di stato attivo chiamando SetIsFocusScope.

L'esempio seguente trasforma un oggetto StackPanel in un ambito di stato attivo impostando la IsFocusScope proprietà associata.

<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 dello stato attivo per l'elemento specificato.

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

GetFocusedElement ottiene l'elemento con stato attivo per l'ambito dello stato attivo specificato. SetFocusedElement imposta l'elemento con stato attivo nell'ambito dello stato attivo specificato. SetFocusedElement viene in genere utilizzato per impostare l'elemento con stato attivo iniziale.

L'esempio seguente illustra come impostare e ottenere l'elemento con lo stato attivo in un ambito di stato attivo.

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

Navigazione tramite tastiera

La KeyboardNavigation classe è responsabile dell'implementazione dello spostamento dello stato attivo predefinito della tastiera quando viene premuto uno dei tasti di spostamento. ovvero TAB, MAIUSC+TAB, CTRL+TAB, CTRL+MAIUSC+TAB, tasto FRECCIA SU, tasto FRECCIA GIÙ, tasto FRECCIA SINISTRA e tasto FRECCIA DESTRA.

Il comportamento di spostamento di un contenitore di spostamento può essere modificato impostando le proprietà TabNavigationassociate KeyboardNavigation , ControlTabNavigatione DirectionalNavigation. Queste proprietà sono di tipo KeyboardNavigationMode e i valori possibili sono Continue, , LocalContained, CycleOnce, e None. Il valore predefinito è Continue, il che significa che l'elemento non è un contenitore di navigazione.

Nell'esempio seguente viene creato un Menu oggetto con un numero di MenuItem oggetti . La TabNavigation proprietà associata è impostata su Cycle su su Menu. Quando lo stato attivo viene modificato usando il tasto TAB all'interno di Menu, lo stato attivo verrà spostato 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 lo stato attivo è MoveFocus e PredictFocus.

MoveFocus cambia lo stato attivo sull'elemento successivo nell'applicazione. Un TraversalRequest oggetto viene utilizzato per specificare la direzione. L'oggetto FocusNavigationDirection passato a MoveFocus specifica le diverse direzioni di messa a fuoco può essere spostato, ad esempio First, LastUp e Down.

Nell'esempio seguente viene MoveFocus usato 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 se lo stato attivo dovesse essere modificato. Attualmente, solo Up, Down, Lefte Right sono supportati da PredictFocus.

Eventi di stato attivo

Gli eventi correlati allo stato attivo della tastiera sono PreviewGotKeyboardFocuse GotKeyboardFocusPreviewLostKeyboardFocus, LostKeyboardFocus. Gli eventi vengono definiti come eventi associati nella Keyboard classe , ma sono più facilmente accessibili come eventi indirizzati equivalenti nelle classi di elementi di base. Per altre informazioni sugli eventi, vedere Cenni preliminari sugli 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 o l'evento PreviewGotKeyboardFocusPreviewLostKeyboardFocusEvent viene gestito e Handled viene impostato su true, lo stato attivo non cambierà.

Nell'esempio seguente vengono associati GotKeyboardFocus gestori eventi e LostKeyboardFocus a un oggetto 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 ottiene lo TextBox stato attivo della tastiera, la Background proprietà di 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 l'oggetto perde lo TextBox stato attivo della tastiera, la Background proprietà di TextBox viene modificata 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 vengono definiti in FocusManager come eventi associati, ma non espone i wrapper dell'evento FocusManager CLR. UIElement e ContentElement esporre questi eventi in modo più pratico.

Vedi anche