Eventi della tastiera

Eventi della tastiera e stato attivo

Gli eventi di tastiera seguenti possono verificarsi sia per l'hardware che per le tastiere touch.

Evento Descrizione
KeyDown Si verifica quando un tasto viene premuto.
KeyUp Si verifica quando si rilascia un tasto.

Importante

Alcuni controlli XAML gestiscono internamente gli eventi di input. In questi casi potrebbe sembrare che non si verifichi un evento di input perché il listener di eventi non richiama il gestore associato. In genere, questo sottoinsieme di tasti viene elaborato dal gestore della classe per fornire il supporto incorporato dell'accessibilità tramite tastiera di base. Ad esempio, la classe Button esegue l'override degli eventi OnKeyDown sia per la chiave Space che per il tasto Enter (così come OnPointerPressed) e li indirizza all'evento Click del controllo. Quando un tasto premuto viene gestito dalla classe di controllo, gli eventi KeyDown e KeyUp non vengono generati.
Ciò fornisce un equivalente tastiera predefinito per richiamare il pulsante, in modo simile a toccarlo con un dito o facendo clic con un mouse. Le chiavi diverse da Space o Enter attivano comunque gli eventi KeyDown e KeyUp. Per altre info sul funzionamento della gestione basata su classi degli eventi (in particolare, la sezione "Gestori eventi di input nei controlli"), vedi Panoramica degli eventi e degli eventi indirizzati.

I controlli nell'interfaccia utente generano eventi della tastiera solo quando hanno lo stato attivo per l'input. Un singolo controllo ottiene lo stato attivo quando l'utente fa clic o tocca direttamente su tale controllo nel layout oppure usa il tasto TAB per eseguire un'istruzione in una sequenza di tabulazioni all'interno dell'area del contenuto.

Puoi anche chiamare il metodo Focus di un controllo per forzare lo stato attivo. Questa operazione è necessaria quando si implementano i tasti di scelta rapida, perché lo stato attivo della tastiera non è impostato per impostazione predefinita quando l'interfaccia utente viene caricata. Per altre info, vedi l'esempio di tasti di scelta rapida più avanti in questo argomento.

Affinché un controllo riceva lo stato attivo dell'input, deve essere abilitato, visibile e avere i valori delle proprietà IsTabStop e HitTestVisible di true. Questo è lo stato predefinito per la maggior parte dei controlli. Quando un controllo ha lo stato attivo per l'input, può generare e rispondere agli eventi di input della tastiera, come descritto più avanti in questo argomento. Puoi anche rispondere a un controllo che riceve o perde lo stato attivo gestendo gli eventi GotFocus e LostFocus.

Per impostazione predefinita, la sequenza di schede dei controlli è l'ordine in cui vengono visualizzati nel linguaggio XAML (Extensible Application Markup Language). Tuttavia, è possibile modificare questo ordine usando la proprietà TabIndex. Per altre info, vedi Implementazione dell'accessibilità da tastiera.

Gestori eventi della tastiera

Un gestore eventi di input implementa un delegato che fornisce le informazioni seguenti:

  • Il nome del mittente dell'evento. Il mittente segnala l'oggetto a cui è associato il gestore eventi.
  • Dati dell'evento. Per gli eventi della tastiera, tali dati saranno un'istanza di KeyRoutedEventArgs. Il delegato per i gestori è KeyEventHandler. Le proprietà più rilevanti di KeyRoutedEventArgs per la maggior parte degli scenari del gestore sono Key e possibilmente KeyStatus.
  • OriginalSource. Poiché gli eventi della tastiera sono eventi indirizzati, i dati dell'evento forniscono OriginalSource. Se si consente deliberatamente agli eventi di scorrere un albero di oggetti, OriginalSource a volte è l'oggetto di preoccupazione anziché il mittente. Tuttavia, dipende dalla progettazione. Per altre informazioni su come usare OriginalSource anziché mittente, vedere la sezione "Eventi indirizzati tramite tastiera" di questo argomento o Eventi e panoramica degli eventi indirizzati.

Collegamento di un gestore eventi della tastiera

È possibile allegare le funzioni del gestore eventi della tastiera per qualsiasi oggetto che include l'evento come membro. Ciò include qualsiasi classe derivata UiElement. L'esempio XAML seguente mostra come collegare i gestori per l'evento KeyUp per una griglia.

<Grid KeyUp="Grid_KeyUp">
  ...
</Grid>

È anche possibile allegare un gestore eventi nel codice. Per altre informazioni, vedi Panoramica degli eventi e degli eventi indirizzati.

Definizione di un gestore eventi della tastiera

Nell'esempio seguente viene illustrata la definizione incompleta del gestore eventi per il gestore eventi KeyUp associato nell'esempio precedente.

void Grid_KeyUp(object sender, KeyRoutedEventArgs e)
{
    //handling code here
}
Private Sub Grid_KeyUp(ByVal sender As Object, ByVal e As KeyRoutedEventArgs)
    ' handling code here
End Sub
void MyProject::MainPage::Grid_KeyUp(
  Platform::Object^ sender,
  Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e)
  {
      //handling code here
  }

Uso di KeyRoutedEventArgs

Tutti gli eventi della tastiera usano KeyRoutedEventArgs per i dati dell'evento e KeyRoutedEventArgs contiene le proprietà seguenti:

Chiavi virtuali

L'evento KeyDown viene generato se viene premuto un tasto. Analogamente, KeyUp viene generato se viene rilasciata una chiave. In genere, si ascoltano gli eventi per elaborare un valore di chiave specifico. Per determinare quale tasto viene premuto o rilasciato, controllare il valore chiave nei dati dell'evento. Key restituisce un valore VirtualKey . L'enumerazione VirtualKey include tutte le chiavi supportate.

Tasti di modifica

I tasti di modifica sono tasti come CTRL o MAIUSC che in genere gli utenti usano in combinazione con altri tasti. L'app può usare queste combinazioni come tasti di scelta rapida personalizzati per richiamare i comandi dell'app.

Nota

Per i tasti di scelta rapida predefiniti, vedere Tasti di scelta rapida e tasti di scelta rapida.

È possibile rilevare le combinazioni di tasti di scelta rapida nei gestori eventi KeyDown e KeyUp. Quando si verifica un evento della tastiera per un tasto non modificatore, è possibile controllare se un tasto di modifica è nello stato premuto.

In alternativa, la funzione GetKeyState() di CoreWindow (ottenuta tramite CoreWindow.GetForCurrentThread()) può essere usata anche per controllare lo stato del modificatore quando viene premuto un tasto non modificatore.

Gli esempi seguenti implementano questo secondo metodo, includendo anche il codice stub per la prima implementazione.

Nota

Il tasto ALT è rappresentato dal valore VirtualKey.Menu .

Esempio di combinazioni di tasti

Nell'esempio seguente viene illustrato come implementare un set di tasti di scelta rapida personalizzati. In questo esempio, gli utenti possono controllare la riproduzione multimediale usando i pulsanti Riproduci, Sospendi e Arresta oppure CTRL+P, CTRL+A e tasti di scelta rapida ctrl+S. Il codice XAML del pulsante mostra i collegamenti usando le descrizioni comando e le proprietà AutomationProperties nelle etichette dei pulsanti. Questa auto-documentazione è importante per aumentare l'usabilità e l'accessibilità dell'app. Per altre informazioni, vedere Accessibilità tramite tastiera.

Si noti anche che la pagina imposta lo stato attivo di input su se stesso quando viene caricato. Senza questo passaggio, nessun controllo ha lo stato attivo iniziale dell'input e l'app non genera eventi di input finché l'utente non imposta manualmente lo stato attivo di input (ad esempio, tramite tabulazione su o facendo clic su un controllo).

<Grid KeyDown="Grid_KeyDown">

  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>

  <MediaElement x:Name="DemoMovie" Source="xbox.wmv"
    Width="500" Height="500" Margin="20" HorizontalAlignment="Center" />

  <StackPanel Grid.Row="1" Margin="10"
    Orientation="Horizontal" HorizontalAlignment="Center">

    <Button x:Name="PlayButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+P"
      AutomationProperties.AcceleratorKey="Control P">
      <TextBlock>Play</TextBlock>
    </Button>

    <Button x:Name="PauseButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+A"
      AutomationProperties.AcceleratorKey="Control A">
      <TextBlock>Pause</TextBlock>
    </Button>

    <Button x:Name="StopButton" Click="MediaButton_Click"
      ToolTipService.ToolTip="Shortcut key: Ctrl+S"
      AutomationProperties.AcceleratorKey="Control S">
      <TextBlock>Stop</TextBlock>
    </Button>

  </StackPanel>

</Grid>
//showing implementations but not header definitions
void MainPage::OnNavigatedTo(NavigationEventArgs^ e)
{
    (void) e;    // Unused parameter
    this->Loaded+=ref new RoutedEventHandler(this,&amp;MainPage::ProgrammaticFocus);
}
void MainPage::ProgrammaticFocus(Object^ sender, RoutedEventArgs^ e) 
{
    this->Focus(Windows::UI::Xaml::FocusState::Programmatic);
}

void KeyboardSupport::MainPage::MediaButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    FrameworkElement^ fe = safe_cast<FrameworkElement^>(sender);
    if (fe->Name == "PlayButton") {DemoMovie->Play();}
    if (fe->Name == "PauseButton") {DemoMovie->Pause();}
    if (fe->Name == "StopButton") {DemoMovie->Stop();}
}


bool KeyboardSupport::MainPage::IsCtrlKeyPressed()
{
    auto ctrlState = CoreWindow::GetForCurrentThread()->GetKeyState(VirtualKey::Control);
    return (ctrlState & CoreVirtualKeyStates::Down) == CoreVirtualKeyStates::Down;
}

void KeyboardSupport::MainPage::Grid_KeyDown(Platform::Object^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e)
{
    if (e->Key == VirtualKey::Control) isCtrlKeyPressed = true;
}


void KeyboardSupport::MainPage::Grid_KeyUp(Platform::Object^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e)
{
    if (IsCtrlKeyPressed()) 
    {
        if (e->Key==VirtualKey::P) { DemoMovie->Play(); }
        if (e->Key==VirtualKey::A) { DemoMovie->Pause(); }
        if (e->Key==VirtualKey::S) { DemoMovie->Stop(); }
    }
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    // Set the input focus to ensure that keyboard events are raised.
    this.Loaded += delegate { this.Focus(FocusState.Programmatic); };
}

private void MediaButton_Click(object sender, RoutedEventArgs e)
{
    switch ((sender as Button).Name)
    {
        case "PlayButton": DemoMovie.Play(); break;
        case "PauseButton": DemoMovie.Pause(); break;
        case "StopButton": DemoMovie.Stop(); break;
    }
}

private static bool IsCtrlKeyPressed()
{
    var ctrlState = CoreWindow.GetForCurrentThread().GetKeyState(VirtualKey.Control);
    return (ctrlState & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
}

private void Grid_KeyDown(object sender, KeyRoutedEventArgs e)
{
    if (IsCtrlKeyPressed())
    {
        switch (e.Key)
        {
            case VirtualKey.P: DemoMovie.Play(); break;
            case VirtualKey.A: DemoMovie.Pause(); break;
            case VirtualKey.S: DemoMovie.Stop(); break;
        }
    }
}
Private isCtrlKeyPressed As Boolean
Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)

End Sub

Private Function IsCtrlKeyPressed As Boolean
    Dim ctrlState As CoreVirtualKeyStates = CoreWindow.GetForCurrentThread().GetKeyState(VirtualKey.Control);
    Return (ctrlState & CoreVirtualKeyStates.Down) == CoreVirtualKeyStates.Down;
End Function

Private Sub Grid_KeyDown(sender As Object, e As KeyRoutedEventArgs)
    If IsCtrlKeyPressed() Then
        Select Case e.Key
            Case Windows.System.VirtualKey.P
                DemoMovie.Play()
            Case Windows.System.VirtualKey.A
                DemoMovie.Pause()
            Case Windows.System.VirtualKey.S
                DemoMovie.Stop()
        End Select
    End If
End Sub

Private Sub MediaButton_Click(sender As Object, e As RoutedEventArgs)
    Dim fe As FrameworkElement = CType(sender, FrameworkElement)
    Select Case fe.Name
        Case "PlayButton"
            DemoMovie.Play()
        Case "PauseButton"
            DemoMovie.Pause()
        Case "StopButton"
            DemoMovie.Stop()
    End Select
End Sub

Nota

L'impostazione di AutomationProperties.AcceleratorKey o AutomationProperties.AccessKey in XAML fornisce informazioni sulla stringa, che documenta il tasto di scelta rapida per richiamare tale azione specifica. Le informazioni vengono acquisite da Microsoft Automazione interfaccia utente client, ad esempio Assistente vocale, e vengono in genere fornite direttamente all'utente.

L'impostazione di AutomationProperties.AcceleratorKey o AutomationProperties.AccessKey non ha alcuna azione da sola. Dovrai comunque collegare i gestori per gli eventi KeyDown o KeyUp sul controllo pertinente per implementare effettivamente il comportamento dei tasti di scelta rapida nell'app. Inoltre, la decorazione del testo sottolineato per un tasto di scelta non viene fornita automaticamente. È necessario sottolineare in modo esplicito il testo per la chiave specifica nel tasto mnemonico come formattazione sottolineatura inline se si desidera visualizzare il testo sottolineato nell'interfaccia utente.

 

Eventi indirizzati tramite tastiera

Alcuni eventi sono eventi indirizzati, tra cui KeyDown e KeyUp. Gli eventi indirizzati usa la strategia di bubbling. La strategia di routing di bubbling indica che un evento ha origine da un oggetto figlio e quindi viene instradato a oggetti padre successivi nell'albero degli oggetti. Ciò offre un'altra opportunità per gestire lo stesso evento e interagire con gli stessi dati dell'evento.

Si consideri l'esempio XAML seguente, che gestisce gli eventi KeyUp per un oggetto Canvas e due oggetti Button. In questo caso, se si rilascia un tasto mentre lo stato attivo viene mantenuto da uno degli oggetti Button , viene generato l'evento KeyUp . L'evento viene quindi visualizzato nell'oggetto Canvas padre.

<StackPanel KeyUp="StackPanel_KeyUp">
  <Button Name="ButtonA" Content="Button A"/>
  <Button Name="ButtonB" Content="Button B"/>
  <TextBlock Name="statusTextBlock"/>
</StackPanel>

L'esempio seguente illustra come implementare il gestore eventi KeyUp per il contenuto XAML corrispondente nell'esempio precedente.

void StackPanel_KeyUp(object sender, KeyRoutedEventArgs e)
{
    statusTextBlock.Text = String.Format(
        "The key {0} was pressed while focus was on {1}",
        e.Key.ToString(), (e.OriginalSource as FrameworkElement).Name);
}

Si noti l'uso della proprietà OriginalSource nel gestore precedente. In questo caso, OriginalSource segnala l'oggetto che ha generato l'evento. L'oggetto non può essere StackPanel perché StackPanel non è un controllo e non può avere lo stato attivo. Solo uno dei due pulsanti all'interno di StackPanel potrebbe aver generato l'evento, ma quale? Si usa OriginalSource per distinguere l'oggetto origine evento effettivo, se si gestisce l'evento in un oggetto padre.

Proprietà handled nei dati dell'evento

A seconda della strategia di gestione degli eventi, potrebbe essere necessario che un solo gestore eventi reagisca a un evento di bubbling. Ad esempio, se si dispone di un gestore KeyUp specifico collegato a uno dei controlli Button, avrebbe la prima opportunità di gestire tale evento. In questo caso, potrebbe non essere necessario che anche il pannello padre gestisca l'evento. Per questo scenario, è possibile usare la proprietà Handled nei dati dell'evento.

Lo scopo della proprietà Handled in una classe di dati di evento indirizzata consiste nel segnalare che un altro gestore registrato in precedenza nella route dell'evento ha già agito. Ciò influisce sul comportamento del sistema di eventi indirizzato. Quando si imposta Handled su true in un gestore eventi, l'evento interrompe il routing e non viene inviato agli elementi padre successivi.

AddHandler ed eventi di tastiera già gestiti

È possibile usare una tecnica speciale per associare gestori che possono agire sugli eventi già contrassegnati come gestiti. Questa tecnica usa il metodo AddHandler per registrare un gestore, anziché usare attributi XAML o sintassi specifica del linguaggio per l'aggiunta di gestori, ad esempio += in C#.

Una limitazione generale di questa tecnica è che l'API AddHandler accetta un parametro di tipo RoutedEvent che identifica l'evento indirizzato in questione. Non tutti gli eventi indirizzati forniscono un identificatore RoutedEvent e questa considerazione influisce quindi sugli eventi indirizzati che possono comunque essere gestiti nel caso Handled. Gli eventi KeyDown e KeyUp hanno indirizzato identificatori di evento (KeyDownEvent e KeyUpEvent) in UIElement. Tuttavia, altri eventi come TextBox.TextChanged non hanno identificatori di evento indirizzati e pertanto non possono essere usati con la tecnica AddHandler.

Override degli eventi e del comportamento della tastiera

È possibile eseguire l'override degli eventi chiave per controlli specifici (ad esempio GridView) per fornire uno spostamento dello stato attivo coerente per vari dispositivi di input, tra cui tastiera e game pad.

Nell'esempio seguente, sottoclassiamo il controllo ed eseguiamo l'override del comportamento KeyDown per spostare lo stato attivo sul contenuto gridView quando viene premuto un tasto freccia.

  public class CustomGridView : GridView
  {
    protected override void OnKeyDown(KeyRoutedEventArgs e)
    {
      // Override arrow key behaviors.
      if (e.Key != Windows.System.VirtualKey.Left && e.Key !=
        Windows.System.VirtualKey.Right && e.Key !=
          Windows.System.VirtualKey.Down && e.Key !=
            Windows.System.VirtualKey.Up)
              base.OnKeyDown(e);
      else
        FocusManager.TryMoveFocus(FocusNavigationDirection.Down);
    }
  }

Nota

Se si usa un controllo GridView solo per il layout, è consigliabile usare altri controlli, ad esempio ItemsControl con ItemsWrapGrid.

Esecuzione di comandi

Un numero ridotto di elementi dell'interfaccia utente fornisce il supporto predefinito per il comando. L'esecuzione di comandi usa eventi indirizzati correlati all'input nell'implementazione sottostante. Consente l'elaborazione dell'input dell'interfaccia utente correlato, ad esempio un'azione del puntatore o un tasto di scelta rapida specifico, richiamando un singolo gestore di comandi.

Se il comando è disponibile per un elemento dell'interfaccia utente, è consigliabile usare le API di comando anziché gli eventi di input discreti. Per altre info, vedi ButtonBase.Command.

È anche possibile implementare ICommand per incapsulare la funzionalità di comando che si richiama dai gestori eventi ordinari. In questo modo è possibile usare i comandi anche quando non è disponibile alcuna proprietà Command .

Input di testo e controlli

Alcuni controlli reagiscono agli eventi della tastiera con la propria gestione. Ad esempio, TextBox è un controllo progettato per acquisire e quindi rappresentare visivamente il testo immesso tramite la tastiera. Usa KeyUp e KeyDown nella propria logica per acquisire le sequenze di tasti, quindi genera anche il proprio evento TextChanged se il testo è stato effettivamente modificato.

In genere è comunque possibile aggiungere gestori per KeyUp e KeyDown a un controllo TextBox o a qualsiasi controllo correlato destinato all'elaborazione dell'input di testo. Tuttavia, come parte della progettazione prevista, un controllo potrebbe non rispondere a tutti i valori chiave indirizzati a esso tramite eventi chiave. Il comportamento è specifico di ogni controllo.

Ad esempio, ButtonBase (la classe base per Button) elabora KeyUp in modo che possa verificare la presenza della barra spaziatrice o invio. ButtonBase considera KeyUp equivalente a un pulsante sinistro del mouse per generare un evento Click . Questa elaborazione dell'evento viene eseguita quando ButtonBase esegue l'override del metodo virtuale OnKeyUp. Nell'implementazione imposta Handled su true. Il risultato è che qualsiasi elemento padre di un pulsante in ascolto di un evento chiave, nel caso di una barra spaziatrice, non riceve l'evento già gestito per i propri gestori.

Un altro esempio è TextBox. Alcuni tasti, ad esempio i tasti di direzione, non sono considerati testo da TextBox e sono invece considerati specifici del comportamento dell'interfaccia utente del controllo. TextBox contrassegna questi casi evento come gestiti.

I controlli personalizzati possono implementare un comportamento di override simile per gli eventi chiave eseguendo l'override di OnKeyDown / OnKeyUp. Se il controllo personalizzato elabora tasti di scelta rapida specifici o ha un comportamento di controllo o stato attivo simile allo scenario descritto per TextBox, è consigliabile inserire questa logica nelle proprie sostituzioni OnKeyDown / OnKeyUp.

La tastiera virtuale

I controlli input di testo forniscono supporto automatico per la tastiera virtuale. Quando l'utente imposta lo stato attivo di input su un controllo di testo usando l'input tocco, la tastiera virtuale viene visualizzata automaticamente. Quando lo stato attivo dell'input non è su un controllo di testo, la tastiera virtuale è nascosta.

Quando viene visualizzata la tastiera virtuale, riposiziona automaticamente l'interfaccia utente per assicurarsi che l'elemento con stato attivo rimanga visibile. Ciò può causare lo spostamento dello schermo da altre aree importanti dell'interfaccia utente. Tuttavia, puoi disabilitare il comportamento predefinito e apportare modifiche personalizzate all'interfaccia utente quando viene visualizzata la tastiera virtuale. Per altre info, vedi l'esempio di tastiera virtuale.

Se si crea un controllo personalizzato che richiede l'input di testo, ma non deriva da un controllo di input di testo standard, è possibile aggiungere il supporto della tastiera virtuale implementando i pattern di controllo Automazione interfaccia utente corretti. Per altre info, vedi l'esempio di tastiera virtuale.

I tasti premuti sulla tastiera virtuale generano eventi KeyDown e KeyUp proprio come i tasti premuti sulle tastiere hardware. Tuttavia, la tastiera virtuale non genererà eventi di input per CTRL+A, CTRL+Z, CTRL+X, CTRL+C e CTRL+V, che sono riservati per la manipolazione del testo nel controllo di input.

È possibile facilitare e velocizzare notevolmente l'immissione dei dati nell'app impostando l'ambito di input del controllo di testo in base al tipo di dati che si prevede che l'utente immetta. L'ambito di input fornisce a un suggerimento sul tipo di input di testo previsto dal controllo, in modo che il sistema possa fornire un layout di tastiera virtuale specifico per il tipo di input. Ad esempio, se una casella di testo viene usata solo per immettere un PIN di 4 cifre, imposta la proprietà InputScope su Number. In questo modo dai indicazione al sistema di mostrare il layout con il tastierino numerico, che rende più semplice l'immissione del PIN da parte dell'utente. Per altre informazioni, consultare Usare l'ambito di input per modificare la tastiera virtuale.

Sviluppatori

Finestre di progettazione

Esempi

Esempi di archivio