Cenni preliminari sull’input
Il sottosistema Windows Presentation Foundation (WPF) fornisce un'API potente che consente di ottenere input da vari dispositivi, inclusi mouse, tastiera, tocco e stilo. In questo argomento vengono descritti i servizi disponibili in WPF e viene illustrata l'architettura dei sistemi di input.
Nel presente argomento sono contenute le seguenti sezioni.
- API di input
- Routing degli eventi
- Gestione degli eventi di input
- Input di testo
- Tocco e modifica
- Focus
- Posizione del mouse
- Mouse capture
- Comandi
- Il sistema di input e gli elementi di base
- Argomenti successivi
- Argomenti correlati
API di input
L'esposizione dell'API di input principale viene rilevata nelle classi degli elementi di base: UIElement, ContentElement, FrameworkElement e FrameworkContentElement. Per ulteriori informazioni sugli elementi di base, vedere Cenni preliminari sugli elementi di base. Queste classi forniscono funzionalità per eventi di input relativi alle sequenze di tasti, ai pulsanti del mouse, alla rotella del mouse, al movimento del mouse, alla gestione dello stato attivo e allo stato mouse capture, solo per citarne alcuni. Collocando l'API di input sugli elementi di base, invece di considerare tutti gli eventi di input come servizio, l'architettura di input consente di originare gli eventi di input da un particolare oggetto dell'interfaccia utente e di supportare uno schema di routing dell'evento con più elementi aventi la possibilità di gestire un evento di input. A molti eventi di input è associata una coppia di eventi. Ad esempio, l'evento di pressione di tasti è associato agli eventi KeyDown e PreviewKeyDown. La differenza tra questi eventi consiste nella modalità con cui vengono indirizzati all'elemento di destinazione. Gli eventi di anteprima effettuano il tunneling della struttura ad albero dell'elemento a partire dall'elemento radice all'elemento di destinazione. Gli eventi di bubbling invece effettuano il bubbling dall'elemento di destinazione all'elemento radice. Il routing degli eventi di WPF viene illustrato più dettagliatamente in seguito in questi cenni preliminari e in Cenni preliminari sugli eventi indirizzati.
Classi Keyboard e Mouse
Oltre all'API di input delle classi degli elementi di base, la classe Keyboard e le classi Mouse forniscono un'API aggiuntiva per utilizzare gli input della tastiera e del mouse.
Esempi di API di input della classe Keyboard sono la proprietà Modifiers, che restituisce l'oggetto ModifierKeys attualmente selezionato, e il metodo IsKeyDown, che consente di determinare se viene premuto un tasto specificato.
Nell'esempio seguente viene utilizzato il metodo GetKeyStates per determinare se Key si trova nello stato premuto.
' Uses the Keyboard.GetKeyStates to determine if a key is down.
' A bitwise AND operation is used in the comparison.
' e is an instance of KeyEventArgs.
If (Keyboard.GetKeyStates(Key.Return) And KeyStates.Down) > 0 Then
btnNone.Background = Brushes.Red
// Uses the Keyboard.GetKeyStates to determine if a key is down.
// A bitwise AND operation is used in the comparison.
// e is an instance of KeyEventArgs.
if ((Keyboard.GetKeyStates(Key.Return) & KeyStates.Down) > 0)
{
btnNone.Background = Brushes.Red;
}
Esempi di API di input nella classe Mouse sono l'oggetto MiddleButton che ottiene lo stato del pulsante centrale del mouse e l'oggetto DirectlyOver che ottiene l'elemento su cui è attualmente posizionato il puntatore del mouse.
Nell'esempio seguente si stabilisce se l'oggetto LeftButton del mouse si trova nello stato Pressed.
If Mouse.LeftButton = MouseButtonState.Pressed Then
UpdateSampleResults("Left Button Pressed")
End If
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
UpdateSampleResults("Left Button Pressed");
}
Le classi Mouse e Keyboard vengono analizzate più dettagliatamente in seguito in questi cenni preliminari.
Input dello stilo
In WPF è stato integrato il supporto per l'oggetto Stylus. L'oggetto Stylus è un input penna divenuto comune grazie a Tablet PC. Le applicazioni WPF possono considerare lo stilo come un mouse utilizzando l' API del mouse; tuttavia WPF espone anche un'astrazione del dispositivo stilo che utilizza un modello simile alla tastiera e al mouse. Tutte le APIs correlate allo stilo contengono la parola "Stylus".
Dal momento che lo stilo può funzionare come un mouse, le applicazioni che supportano solo l'input da mouse possono comunque ottenere automaticamente un certo livello di supporto dello stilo. Quando lo stilo viene utilizzato in questa modalità, l'applicazione ha la possibilità di gestire l'evento dello stilo appropriato gestendo l'evento del mouse corrispondente. Inoltre, i servizi di livello superiore, ad esempio l'input penna, sono disponibili anche tramite l'astrazione del dispositivo stilo. Per ulteriori informazioni sull'input penna, vedere Nozioni di base sull'input penna.
Routing degli eventi
Un oggetto FrameworkElement può contenere nel modello di contenuto altri elementi come elementi figlio, formando una struttura ad albero di elementi. In WPF, l'elemento padre può partecipare all'input diretto ai relativi elementi figlio o agli altri discendenti mediante la gestione degli eventi. Ciò risulta particolarmente utile per la compilazione dei controlli a partire da controlli più piccoli, processo noto come "composizione dei controlli". Per ulteriori informazioni sulle strutture ad albero di elementi e sulla rispettiva correlazione con le route degli eventi, vedere Strutture ad albero in WPF.
Il routing degli eventi è il processo di inoltro di eventi a più elementi, che consente a un particolare oggetto o elemento della route di offrire una risposta significativa (tramite la gestione) a un evento che potrebbe essere stato originato da un elemento diverso. Gli eventi indirizzati utilizzano uno dei tre meccanismi di routing indicati di seguito: diretto, bubbling e tunneling. Nel routing diretto, l'elemento di origine è l'unico elemento notificato e l'evento non viene indirizzato a nessun altro elemento. Tuttavia, l'evento indirizzato tramite routing diretto offre alcune funzionalità aggiuntive che sono disponibili solo per gli eventi indirizzati rispetto agli eventi CLR standard. Il bubbling viene eseguito procedendo verso l'alto nella struttura ad albero dell'elemento, notificando dapprima l'elemento che ha originato l'evento, quindi l'elemento padre e così via. Il tunneling parte dalla radice della struttura ad albero dell'elemento e procede verso il basso, terminando con l'elemento di origine. Per ulteriori informazioni sugli eventi indirizzati, vedere Cenni preliminari sugli eventi indirizzati.
Gli eventi di input WPF vengono in genere eseguiti in coppie, costituite da un evento di tunneling e un evento di bubbling. Gli eventi di tunneling si distinguono da quelli di bubbling tramite il prefisso "Preview". L'evento PreviewMouseMove, ad esempio, è la versione di tunneling di un evento di spostamento del mouse, mentre MouseMove è la versione di bubbling dello stesso evento. Questa coppia di eventi rappresenta una convenzione implementata al livello dell'elemento e non è una funzionalità intrinseca del sistema di eventi WPF. Per informazioni dettagliate, vedere la sezione relativa agli eventi di input WPF in Cenni preliminari sugli eventi indirizzati.
Gestione degli eventi di input
Per ricevere input su un elemento, un gestore eventi deve essere associato a quel particolare evento. In XAML tale associazione è molto semplice: è sufficiente fare riferimento al nome dell'evento come attributo dell'elemento che rimarrà in ascolto di questo evento. Si imposta quindi il valore dell'attributo sul nome del gestore eventi che viene definito, in base a un delegato. Il gestore eventi deve essere scritto in codice, ad esempio C#, e può essere incluso in un file code-behind.
Gli eventi di tastiera si verificano quando il sistema operativo segnala le azioni principali che vengono eseguite quando lo stato attivo della tastiera è impostato su un elemento. Gli eventi del mouse e dello stilo rientrano ciascuno in due categorie: eventi che segnalano le modifiche nella posizione del puntatore in relazione all'elemento ed eventi che segnalano le modifiche nello stato dei pulsanti del dispositivo.
Esempio di eventi di input da tastiera
Nel seguente esempio viene attesa la pressione del tasto freccia sinistra. Viene creato un oggetto StackPanel che dispone di un oggetto Button. Un gestore eventi che rimane in ascolto della pressione del tasto freccia sinistra viene associato all'istanza di Button.
Nella prima parte dell'esempio vengono creati gli oggetti StackPanel e Button e viene associato il gestore eventi per KeyDown.
<StackPanel>
<Button Background="AliceBlue"
KeyDown="OnButtonKeyDown"
Content="Button1"/>
</StackPanel>
' Create the UI elements.
Dim keyboardStackPanel As New StackPanel()
Dim keyboardButton1 As New Button()
' Set properties on Buttons.
keyboardButton1.Background = Brushes.AliceBlue
keyboardButton1.Content = "Button 1"
' Attach Buttons to StackPanel.
keyboardStackPanel.Children.Add(keyboardButton1)
' Attach event handler.
AddHandler keyboardButton1.KeyDown, AddressOf OnButtonKeyDown
// Create the UI elements.
StackPanel keyboardStackPanel = new StackPanel();
Button keyboardButton1 = new Button();
// Set properties on Buttons.
keyboardButton1.Background = Brushes.AliceBlue;
keyboardButton1.Content = "Button 1";
// Attach Buttons to StackPanel.
keyboardStackPanel.Children.Add(keyboardButton1);
// Attach event handler.
keyboardButton1.KeyDown += new KeyEventHandler(OnButtonKeyDown);
La seconda parte è scritta in codice e definisce il gestore eventi. Quando si preme il tasto freccia sinistra e l'oggetto Button dispone dello stato attivo della tastiera, il gestore viene eseguito e il colore Background dell'oggetto Button viene modificato. Se il tasto viene premuto, ma non corrisponde al tasto freccia sinistra, il colore Background dell'oggetto Button viene impostato di nuovo sul colore iniziale.
Private Sub OnButtonKeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
Dim source As Button = TryCast(e.Source, Button)
If source IsNot Nothing Then
If e.Key = Key.Left Then
source.Background = Brushes.LemonChiffon
Else
source.Background = Brushes.AliceBlue
End If
End If
End Sub
private void OnButtonKeyDown(object sender, KeyEventArgs e)
{
Button source = e.Source as Button;
if (source != null)
{
if (e.Key == Key.Left)
{
source.Background = Brushes.LemonChiffon;
}
else
{
source.Background = Brushes.AliceBlue;
}
}
}
Esempi di eventi di input da mouse
Nell'esempio seguente, il colore di Background di un oggetto Button viene modificato quando il puntatore del mouse viene spostato sull'oggetto Button. Il colore di Background viene ripristinato quando il mouse si allontana da Button.
Nella prima parte dell'esempio vengono creati l'oggetto StackPanel e il controllo Button; il gestore eventi per gli eventi MouseEnter e MouseLeave viene associato all'oggetto Button.
<StackPanel>
<Button Background="AliceBlue"
MouseEnter="OnMouseExampleMouseEnter"
MouseLeave="OnMosueExampleMouseLeave">Button
</Button>
</StackPanel>
' Create the UI elements.
Dim mouseMoveStackPanel As New StackPanel()
Dim mouseMoveButton As New Button()
' Set properties on Button.
mouseMoveButton.Background = Brushes.AliceBlue
mouseMoveButton.Content = "Button"
' Attach Buttons to StackPanel.
mouseMoveStackPanel.Children.Add(mouseMoveButton)
' Attach event handler.
AddHandler mouseMoveButton.MouseEnter, AddressOf OnMouseExampleMouseEnter
AddHandler mouseMoveButton.MouseLeave, AddressOf OnMosueExampleMouseLeave
// Create the UI elements.
StackPanel mouseMoveStackPanel = new StackPanel();
Button mouseMoveButton = new Button();
// Set properties on Button.
mouseMoveButton.Background = Brushes.AliceBlue;
mouseMoveButton.Content = "Button";
// Attach Buttons to StackPanel.
mouseMoveStackPanel.Children.Add(mouseMoveButton);
// Attach event handler.
mouseMoveButton.MouseEnter += new MouseEventHandler(OnMouseExampleMouseEnter);
mouseMoveButton.MouseLeave += new MouseEventHandler(OnMosueExampleMouseLeave);
La seconda parte dell'esempio è scritta in codice e definisce i gestori eventi. Spostando il mouse sull'oggetto Button, il colore di Background dell'oggetto Button viene modificato in SlateGray. Quando il mouse si allontana da Button, il colore di Background dell'oggetto Button viene nuovamente impostato su AliceBlue.
Private Sub OnMouseExampleMouseEnter(ByVal sender As Object, ByVal e As MouseEventArgs)
' Cast the source of the event to a Button.
Dim source As Button = TryCast(e.Source, Button)
' If source is a Button.
If source IsNot Nothing Then
source.Background = Brushes.SlateGray
End If
End Sub
private void OnMouseExampleMouseEnter(object sender, MouseEventArgs e)
{
// Cast the source of the event to a Button.
Button source = e.Source as Button;
// If source is a Button.
if (source != null)
{
source.Background = Brushes.SlateGray;
}
}
Private Sub OnMosueExampleMouseLeave(ByVal sender As Object, ByVal e As MouseEventArgs)
' Cast the source of the event to a Button.
Dim source As Button = TryCast(e.Source, Button)
' If source is a Button.
If source IsNot Nothing Then
source.Background = Brushes.AliceBlue
End If
End Sub
private void OnMosueExampleMouseLeave(object sender, MouseEventArgs e)
{
// Cast the source of the event to a Button.
Button source = e.Source as Button;
// If source is a Button.
if (source != null)
{
source.Background = Brushes.AliceBlue;
}
}
Input di testo
L'evento TextInput consente di rimanere in ascolto dell'input di testo in modo indipendente dal dispositivo. La tastiera è il mezzo principale per l'immissione di testo, ma anche il riconoscimento vocale, il riconoscimento grafia e altri dispositivi di input possono generare input di testo.
Per l'input da tastiera, WPF invia dapprima gli eventi KeyDown / KeyUp appropriati. Se tali eventi non sono gestiti e se si tratta di un tasto di testo (piuttosto che di un tasto di un controllo, quali le frecce direzionali o i tasti funzione), viene generato un evento TextInput. Il mapping tra gli eventi KeyDown/KeyUp e TextInput non è sempre di tipo semplice uno-a-uno, perché sequenze di più tasti possono generare un unico carattere di input di testo e la pressione di un singolo tasto può generare stringhe con più caratteri. Ciò si verifica soprattutto con lingue quali il cinese, il giapponese e il coreano che utilizzano Input Method Editors (IMEs) per generare le migliaia di caratteri possibili nei corrispondenti alfabeti.
Quando WPF invia un evento KeyUp/KeyDown, la proprietà Key viene impostata su Key.System se le sequenze di tasti possono diventare parte di un evento TextInput (ad esempio tramite la pressione di ALT+S). Ciò consente al codice di un gestore di eventi KeyDown di verificare la disponibilità di Key.System e, se la ricerca ha esito positivo, di abbandonare l'elaborazione del gestore dell'evento TextInput generato successivamente. In questi casi, le varie proprietà dell'argomento TextCompositionEventArgs possono essere utilizzate per determinare le sequenze di tasti originali. Analogamente, se un IME è attivo, il valore dell'oggetto Key è Key.ImeProcessede l'oggetto ImeProcessedKey fornisce la selezione del tasto o della sequenza di tasti originale.
Nell'esempio seguente viene definito un gestore per l'evento Click e uno per l'evento KeyDown.
Il primo segmento di codice o di markup crea l'interfaccia utente.
<StackPanel KeyDown="OnTextInputKeyDown">
<Button Click="OnTextInputButtonClick"
Content="Open" />
<TextBox> . . . </TextBox>
</StackPanel>
' Create the UI elements.
Dim textInputStackPanel As New StackPanel()
Dim textInputeButton As New Button()
Dim textInputTextBox As New TextBox()
textInputeButton.Content = "Open"
' Attach elements to StackPanel.
textInputStackPanel.Children.Add(textInputeButton)
textInputStackPanel.Children.Add(textInputTextBox)
' Attach event handlers.
AddHandler textInputStackPanel.KeyDown, AddressOf OnTextInputKeyDown
AddHandler textInputeButton.Click, AddressOf OnTextInputButtonClick
// Create the UI elements.
StackPanel textInputStackPanel = new StackPanel();
Button textInputeButton = new Button();
TextBox textInputTextBox = new TextBox();
textInputeButton.Content = "Open";
// Attach elements to StackPanel.
textInputStackPanel.Children.Add(textInputeButton);
textInputStackPanel.Children.Add(textInputTextBox);
// Attach event handlers.
textInputStackPanel.KeyDown += new KeyEventHandler(OnTextInputKeyDown);
textInputeButton.Click += new RoutedEventHandler(OnTextInputButtonClick);
Il secondo segmento di codice contiene i gestori eventi.
Private Sub OnTextInputKeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
If e.Key = Key.O AndAlso Keyboard.Modifiers = ModifierKeys.Control Then
handle()
e.Handled = True
End If
End Sub
Private Sub OnTextInputButtonClick(ByVal sender As Object, ByVal e As RoutedEventArgs)
handle()
e.Handled = True
End Sub
Public Sub handle()
MessageBox.Show("Pretend this opens a file")
End Sub
private void OnTextInputKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.O && Keyboard.Modifiers == ModifierKeys.Control)
{
handle();
e.Handled = true;
}
}
private void OnTextInputButtonClick(object sender, RoutedEventArgs e)
{
handle();
e.Handled = true;
}
public void handle()
{
MessageBox.Show("Pretend this opens a file");
}
Poiché gli eventi di input effettuano il bubbling della route degli eventi, StackPanel riceve l'input indipendentemente dall'elemento che dispone dello stato attivo della tastiera. Il controllo TextBox riceve per primo la notifica e il gestore OnTextInputKeyDown viene chiamato solo se l'oggetto TextBox non ha gestito l'input. Se l'evento PreviewKeyDown viene utilizzato al posto dell'evento KeyDown, il gestore OnTextInputKeyDown viene chiamato per primo.
In questo esempio, la logica di gestione viene scritta due volte: una prima volta per CTRL+O e una seconda volta per l'evento Click del pulsante. È possibile semplificare questa operazione utilizzando i comandi, invece di gestire direttamente gli eventi di input. I comandi vengono illustrati in questi cenni preliminari e in Cenni preliminari sull'esecuzione di comandi.
Tocco e modifica
I nuovi hardware e i nuovi API del sistema operativo Windows 7 consentono alle applicazioni di ricevere contemporaneamente input da più tocchi. WPF consente alle applicazioni di rilevare e rispondere agli input tocco in un modo simile alle risposte ad altri tipi di input, ad esempio mouse o tastiera, generando eventi quando si verifica il tocco.
WPF espone due tipi di eventi quando si verifica il tocco: eventi tocco ed eventi di modifica. Gli eventi tocco forniscono dati non elaborati relativi a ogni dito appoggiato su un touchscreen e al movimento correlato. Gli eventi di modifica interpretano l'input come azioni determinate. In questa sezione vengono trattati entrambi i tipi di eventi.
Prerequisiti
Per sviluppare un'applicazione che risponde al tocco è necessario disporre dei componenti seguenti.
Microsoft Visual Studio 2010.
Windows 7.
Un dispositivo con supporto per Windows Touch, ad esempio un touchscreen.
Terminologia
Nelle sezioni che illustrano il tocco vengono utilizzati i termini seguenti:
Tocco un tipo di input dell'utente riconosciuto da Windows 7. In genere, il tocco viene generato appoggiando le dita su uno schermo sensibile al tocco. Si noti che dispositivi quali i touchpad diffusi sui computer portatili non supportano il tocco se il dispositivo si limita a convertire la posizione e il movimento del dito come input del mouse.
Multitocco è un tocco che si verifica da più di un punto contemporaneamente. Windows 7 e WPF supportano il multitocco. Ogni qualvolta il tocco viene trattato nella documentazione relativa a WPF, i concetti illustrati si applicano al multitocco.
Una modifica si verifica quando il tocco viene interpretato come un'azione fisica applicata a un oggetto. In WPF gli eventi di modifica interpretano l'input come una modifica di conversione, espansione o rotazione.
Un touch device rappresenta un dispositivo che produce un input tocco, ad esempio un singolo dito su un touchscreen.
Controlli che rispondono al tocco
È possibile scorrere i controlli seguenti trascinando un dito attraverso il controllo, se questo presenta contenuto al di fuori della visualizzazione.
ScrollViewer definisce la proprietà associata ScrollViewer.PanningMode che consente di specificare se la panoramica tocco è abilitata orizzontalmente, verticalmente, in entrambe o in nessuna delle due direzioni. La proprietà ScrollViewer.PanningDeceleration specifica la rapidità di rallentamento dello scorrimento quando l'utente solleva il dito dal touchscreen. La proprietà ScrollViewer.PanningRatio associata specifica il rapporto dell'offset di scorrimento per convertire l'offset di modifica.
Eventi tocco
Le classi base UIElement, UIElement3D e ContentElement definiscono gli eventi che è possibile sottoscrivere in modo che l'applicazione risponda al tocco. Gli eventi tocco risultano utili quando l'applicazione interpreta il tocco come qualcosa di diverso rispetto alla modifica di un oggetto. Ad esempio, un'applicazione che consentisse a un utente di disegnare con un dito o più dita sottoscriverebbe gli eventi tocco.
Tutte tre le classi definiscono gli eventi riportati di seguito che si comportano in modo simile indipendentemente dalla classe di definizione.
In modo simile agli eventi tastiera e mouse, gli eventi tocco sono eventi indirizzati. Gli eventi che iniziano con Preview sono eventi di tunneling e gli eventi che iniziano con Touch sono eventi di bubbling. Per ulteriori informazioni sugli eventi indirizzati, vedere Cenni preliminari sugli eventi indirizzati. Quando si gestiscono questi eventi, è possibile ottenere la posizione dell'input relativa a qualsiasi elemento chiamando il metodo GetTouchPoint o GetIntermediateTouchPoints.
Per comprendere l'interazione fra gli eventi tocco, si consideri lo scenario in cui un utente appoggia un dito su un elemento, muove il dito all'interno dell'elemento e quindi lo solleva dall'elemento. Nell'illustrazione che segue viene mostrata l'esecuzione degli eventi di bubbling. Gli eventi di tunneling vengono omessi per maggiore semplicità.
Eventi tocco
Nell'elenco riportato di seguito è descritta la sequenza degli eventi contenuti nella precedente illustrazione.
L'evento TouchEnter si verifica una volta quando l'utente appoggia un dito sull'elemento.
L'evento TouchDown si verifica una volta.
L'evento TouchMove si verifica più volte quando l'utente muove il dito all'interno dell'elemento.
L'evento TouchUp si verifica una volta quando l'utente solleva il dito dall'elemento.
L'evento TouchLeave si verifica una volta.
Se vengono utilizzate più di due dita, gli eventi si verificano per ogni dito.
Eventi di modifica
Nei casi in cui un'applicazione consente a un utente di modificare un oggetto, la classe UIElement definisce eventi di modifica. A differenza degli eventi tocco che segnalano semplicemente la posizione del tocco, gli eventi di modifica segnalano come può essere interpretato l'input. Esistono tre tipi di modifiche: conversione, espansione e rotazione. Nell'elenco che segue viene descritto come richiamare i tre tipi di modifiche.
Appoggiare un dito su un oggetto e muovere il dito sul touchscreen per richiamare una modifica della conversione. Questo movimento in genere determina lo spostamento dell'oggetto.
Appoggiare due dita su un oggetto e avvicinare o allontanare le dita tra loro per richiamare una modifica di espansione. Questo movimento in genere determina il ridimensionamento dell'oggetto.
Appoggiare due dita su un oggetto e ruotare le dita per richiamare una modifica della rotazione. Questo movimento in genere determina la rotazione dell'oggetto.
Si può verificare più di un tipo di modifica contemporaneamente.
Quando si determina una risposta alle modifiche da parte degli oggetti, è possibile che l'oggetto appaia in un momento di inerzia. Questo consente agli oggetti di simulare il mondo fisico. Ad esempio se si spinge un libro su un tavolo con sufficiente forza, il libro continuerà a muoversi anche dopo essere stato rilasciato. WPF consente di simulare questo comportamento generando eventi di modifica dopo che le dita dell'utente si staccano dall'oggetto.
Per informazioni sulla creazione di un'applicazione che consente all'utente di spostare, ridimensionare e ruotare un oggetto, vedere Procedura dettagliata: creazione della prima applicazione a tocco.
L'oggetto UIElement definisce gli eventi di modifica seguenti.
Per impostazione predefinita, un oggetto UIElement non accetta questi eventi di modifica. Per accettare eventi di modifica in un oggetto UIElement, impostare UIElement.IsManipulationEnabled su true.
Percorso di esecuzione degli eventi di modifica
Si consideri uno scenario in cui un utente "lancia" un oggetto. L'utente appoggia un dito sull'oggetto, muove il dito sul touchscreen per un breve tratto e quindi solleva il dito mentre l'oggetto si sta muovendo. Il risultato di questa azione è che l'oggetto si muoverà sotto il dito dell'utente e continuerà a muoversi dopo che l'utente ha sollevato il dito.
Nell'illustrazione che segue viene mostrato il percorso di esecuzione degli eventi di modifica, oltre a informazioni importanti relative a ciascun evento.
Eventi di modifica
Nell'elenco riportato di seguito è descritta la sequenza degli eventi contenuti nella precedente illustrazione.
Quando l'utente appoggia un dito sull'oggetto si verifica l'evento ManipulationStarting. Questo evento consente inoltre di impostare la proprietà ManipulationContainer. Negli eventi successivi la posizione della modifica sarà relativa a ManipulationContainer. Negli eventi diversi da ManipulationStarting questa proprietà è di sola lettura, pertanto l'evento ManipulationStarting costituisce il solo momento in cui è possibile impostare questa proprietà.
Viene quindi eseguito l'evento ManipulationStarted. Questo evento segnala l'origine della modifica.
L'evento ManipulationDelta si verifica più volte quando l'utente muove il dito su un touchscreen. La proprietà DeltaManipulation della classe ManipulationDeltaEventArgs segnala se la modifica viene interpretata come movimento, espansione o conversione. In questo contesto si esegue la maggior parte del lavoro di modifica di un oggetto.
L'evento ManipulationInertiaStarting si verifica quando il dito dell'utente perde il contatto con l'oggetto. Questo evento consente di specificare la decelerazione delle modifiche durante l'inerzia. In questo modo l'oggetto può emulare spazi fisici o attribuiti diversi se si desidera. Ad esempio, si immagini che l'applicazione disponga di due oggetti che rappresentano elementi nel mondo fisico e che uno di questi sia più pesante dell'altro. È possibile fare rallentare più velocemente l'oggetto più pesante rispetto a quello più leggero.
L'evento ManipulationDelta si verifica più volte durante l'inerzia. Si noti che questo evento si verifica quando le dita dell'utente si muovono attraverso il touchscreen e quando WPF simula l'inerzia. In altre parole, l'evento ManipulationDelta si verifica prima e dopo l'evento ManipulationInertiaStarting. La proprietà ManipulationDeltaEventArgs.IsInertial segnala se l'evento ManipulationDelta si verifica durante l'inerzia, in modo che sia possibile controllare la proprietà ed eseguire azioni diverse, a seconda del valore.
L'evento ManipulationCompleted si verifica quando terminano la modifica e qualsiasi momento di inerzia. Ovvero, dopo che si sono verificati tutti gli eventi ManipulationDelta, si verifica l'evento ManipulationCompleted per segnalare che la modifica è completa.
UIElement definisce anche l'evento ManipulationBoundaryFeedback. Questo evento si verifica quando viene chiamato il metodo ReportBoundaryFeedback nell'evento ManipulationDelta. L'evento ManipulationBoundaryFeedback consente alle applicazioni o ai componenti di fornire feedback visivo quando un oggetto colpisce un limite. La classe Window ad esempio gestisce l'evento ManipulationBoundaryFeedback per fare in modo che la finestra si sposti leggermente quando se ne incontra il bordo.
È possibile annullare la modifica chiamando il metodo Cancel negli argomenti dell'evento in qualsiasi evento di modifica eccetto nell'evento ManipulationBoundaryFeedback. Quando si chiama il metodo Cancel, gli eventi di modifica non vengono più generati e si verificano gli eventi del mouse per il tocco. Nella tabella che segue viene descritta la relazione tra l'ora in cui la modifica viene annullata e gli eventi del mouse che si verificano.
Evento in cui viene chiamato Cancel |
Eventi del mouse che si verificano per input già verificato |
---|---|
Eventi di pressione del pulsante del mouse. |
|
Eventi di pressione del pulsante del mouse e di spostamento del mouse. |
|
Eventi di pressione e di rilascio del pulsante del mouse, eventi di spostamento del mouse. |
Si noti che se si chiama il metodo Cancel quando la modifica è in un momento di inerzia, il metodo restituisce false e l'input non genera eventi del mouse.
Relazione tra eventi tocco ed eventi di modifica
Un oggetto UIElement può sempre ricevere eventi tocco. Quando la proprietà IsManipulationEnabled è impostata su true, un oggetto UIElement può ricevere sia eventi tocco sia eventi di modifica. Se l'evento TouchDown non è gestito, ovvero la proprietà Handled è impostata su false, la logica di modifica acquisisce il tocco all'elemento e genera gli eventi di modifica. Se la proprietà Handled è impostata su true nell'evento TouchDown, la logica di modifica non genera eventi di modifica. Nell'illustrazione seguente viene mostrata la relazione tra gli eventi tocco e gli eventi di modifica.
Eventi tocco ed eventi di modifica
Nell'elenco che segue viene descritta la relazione tra gli eventi tocco e gli eventi di modifica mostrata nella precedente illustrazione.
Quando il primo dispositivo a tocco genera un evento TouchDown su un oggetto UIElement, la logica di modifica chiama il metodo CaptureTouch che genera l'evento GotTouchCapture.
Quando si verifica un evento GotTouchCapture, la logica di modifica chiama il metodo Manipulation.AddManipulator, che genera l'evento ManipulationStarting.
Quando si verificano gli eventi TouchMove, la logica di modifica genera gli eventi ManipulationDelta che si verificano prima dell'evento ManipulationInertiaStarting.
Quando l'ultimo dispositivo a tocco sull'elemento genera l'evento TouchUp, la logica di modifica genera l'evento ManipulationInertiaStarting.
Focus
In WPF lo stato attivo è basato su due concetti principali, lo stato attivo della tastiera e lo stato attivo logico.
Stato attivo della tastiera
Lo stato attivo della tastiera fa riferimento all'elemento che riceve l'input dalla tastiera. Su un desktop un solo elemento può avere lo stato attivo della tastiera. In WPF la proprietà IsKeyboardFocused dell'elemento che presenta lo stato attivo della tastiera è impostata su true. L'oggetto FocusedElement del metodo statico Keyboard sulla classe restituisce l'elemento che attualmente dispone dello stato attivo della tastiera.
Lo stato attivo della tastiera può essere ottenuto utilizzando il tasto TAB per spostarsi su un elemento o facendo clic con il mouse su determinati elementi, ad esempio TextBox. Lo stato attivo della tastiera può anche essere ottenuto a livello di codice utilizzando il metodo Focus sulla classe Keyboard. Focus tenta di fornire lo stato attivo della tastiera all'elemento specificato. L'elemento restituito da Focus è quello che dispone attualmente dello stato attivo della tastiera.
Affinché un elemento ottenga lo stato attivo della tastiera, le proprietà Focusable e IsVisible devono essere impostate su true. Per alcune classi, ad esempio la classe di base Panel, l'impostazione predefinita di Focusable è false. Pertanto, potrebbe essere necessario impostare questa proprietà su true se si desidera che un elemento di questo tipo possa ottenere lo stato attivo.
Nell'esempio seguente, il metodo Focus viene utilizzato per impostare lo stato attivo della tastiera su un oggetto Button. È opportuno impostare lo stato attivo iniziale di un'applicazione nel gestore eventi Loaded.
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
private void OnLoaded(object sender, RoutedEventArgs e)
{
// Sets keyboard focus on the first Button in the sample.
Keyboard.Focus(firstButton);
}
Per ulteriori informazioni sullo stato attivo della tastiera, vedere Cenni preliminari sullo stato attivo.
Stato attivo logico
Lo stato attivo logico fa riferimento all'oggetto FocusManager.FocusedElement in un ambito di stato attivo. In un'applicazione possono essere presenti più elementi con stato attivo logico, ma in un determinato ambito può esistere un solo elemento con lo stato attivo.
Per ambito di stato attivo si intende un elemento contenitore che tiene traccia di FocusedElement all'interno del relativo ambito. Quando lo stato attivo 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 torna nell'ambito di stato attivo, l'elemento con lo stato attivo ottiene nuovamente lo stato attivo della tastiera. In questo modo, lo stato attivo della tastiera può essere passato tra più ambiti, ma è garantito che l'elemento con lo stato attivo nell'ambito di stato attivo rimanga tale al ritorno dello stato attivo.
Un elemento può essere convertito in un ambito dello stato attivo in Extensible Application Markup Language (XAML) impostando la proprietà associata IsFocusScope dell'oggetto FocusManager su true oppure nel codice impostando la proprietà associata tramite il metodo SetIsFocusScope.
Nell'esempio riportato di seguito StackPanel viene convertito in un ambito di stato attivo 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>
Dim focuseScope2 As New StackPanel()
FocusManager.SetIsFocusScope(focuseScope2, True)
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);
In WPF le classi che per impostazione predefinita costituiscono ambiti di stato attivo sono Window, Menu, ToolBar e ContextMenu.
Un elemento che presenta lo stato attivo della tastiera dispone di conseguenza anche dello stato attivo logico per l'ambito di stato attivo a cui appartiene; pertanto, impostando lo stato attivo su un elemento tramite il metodo Focus sulla classe Keyboard o sulle classi degli elementi di base, si tenterà di fornire all'elemento lo stato attivo della tastiera e lo stato attivo logico.
Per determinare l'elemento con lo stato attivo in un ambito di stato attivo, utilizzare GetFocusedElement. Per cambiare l'elemento con lo stato attivo in un ambito di stato attivo, utilizzare SetFocusedElement.
Per ulteriori informazioni sullo stato attivo logico, vedere Cenni preliminari sullo stato attivo.
Posizione del mouse
In WPF, l'API di input fornisce informazioni utili relativamente agli spazi di coordinate. Ad esempio, la coordinata (0,0) rappresenta la coordinata superiore sinistra, ma in relazione a quale elemento della struttura ad albero? Potrebbe trattarsi dell'elemento che costituisce la destinazione dell'input, dell'elemento a cui è associato il gestore eventi o di qualche altro elemento. Per evitare confusione, l'API di input di WPF richiede che venga specificato il frame di riferimento quando si utilizzano le coordinate ottenute tramite il mouse. Il metodo GetPosition restituisce la coordinata del puntatore del mouse relativa all'elemento specificato.
Mouse capture
I dispositivi del mouse includono una caratteristica modale particolare nota come mouse capture. Tale caratteristica viene utilizzata per mantenere uno stato di input di transizione all'avvio di un'operazione di trascinamento della selezione, in modo che le altre operazioni che riguardano la posizione su schermo nominale del puntatore del mouse non vengano necessariamente eseguite. Durante il trascinamento, l'utente non può fare clic senza interrompere il trascinamento della selezione, pertanto la maggior parte dei segnali di passaggio del mouse risulteranno inappropriati, se lo stato mouse capture viene utilizzato dall'origine del trascinamento. Il sistema di input espone le APIs che possono determinare lo stato di mouse capture, nonché le APIs che possono imporre tale stato per uno specifico elemento o eliminare lo stato di mouse capture. Per ulteriori informazioni sulle operazioni di trascinamento delle selezione, vedere Cenni preliminari sul trascinamento della selezione.
Comandi
I comandi abilitano la gestione di input a un livello più semantico rispetto all'input del dispositivo. Si tratta di direttive semplici, ad esempio Cut, Copy, Paste o Open. I comandi sono utili per centralizzare la logica di comando. È possibile accedere a uno stesso comando da un oggetto Menu, in un oggetto ToolBar oppure tramite un tasto di scelta rapida. I comandi forniscono anche un meccanismo per la disabilitazione dei controlli qualora il comando non fosse più disponibile.
RoutedCommand è l'implementazione WPF di ICommand. Quando viene eseguito un oggetto RoutedCommand, nella destinazione comando vengono generati un evento PreviewExecuted e un evento Executed che eseguono il tunneling e il bubbling attraverso la struttura ad albero dell'elemento come altri input. Se non è impostata una destinazione comando, questa sarà rappresentata dall'elemento con lo stato attivo della tastiera. La logica che esegue il comando è associata a un oggetto CommandBinding. Quando un evento Executed raggiunge un oggetto CommandBinding per quel determinato comando, viene chiamato l'oggetto ExecutedRoutedEventHandler su quell'oggetto CommandBinding. Questo gestore esegue l'azione del comando.
Per ulteriori informazioni sui comandi, vedere Cenni preliminari sull'esecuzione di comandi.
In WPF viene fornita una libreria di comandi comuni costituita da ApplicationCommands, MediaCommands, ComponentCommands, NavigationCommandse EditingCommands; in alternativa, è possibile definirne una personalizzata.
Nell'esempio seguente viene mostrato come configurare un oggetto MenuItem in modo che, una volta selezionato richiami il comando Paste sull'oggetto TextBox, presupponendo che tale oggetto disponga dello stato attivo.
<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste" />
</Menu>
<TextBox />
</StackPanel>
' Creating the UI objects
Dim mainStackPanel As New StackPanel()
Dim pasteTextBox As New TextBox()
Dim stackPanelMenu As New Menu()
Dim pasteMenuItem As New MenuItem()
' Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem)
mainStackPanel.Children.Add(stackPanelMenu)
mainStackPanel.Children.Add(pasteTextBox)
' Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();
// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);
// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;
// Setting the command target to the TextBox
pasteMenuItem.CommandTarget = pasteTextBox;
Per ulteriori informazioni sui comandi in WPF, vedere Cenni preliminari sull'esecuzione di comandi.
Il sistema di input e gli elementi di base
Gli eventi di input, ad esempio gli eventi associati definiti dalle classi Mouse, Keyboard e Stylus, vengono generati dal sistema di input e inseriti in una particolare posizione nel modello a oggetti basato sull'hit testing della struttura ad albero visuale in fase di esecuzione.
Ciascuno degli eventi definiti da Mouse, Keyboard e Stylus come evento associato viene esposto nuovamente dalle classi degli elementi di base UIElement e ContentElement come nuovo evento indirizzato. Gli eventi indirizzati degli elementi di base vengono generati dalla gestione dell'evento associato originale e dal riutilizzo dei dati relativi all'evento da parte delle classi.
Quando l'evento di input viene associato a un particolare elemento di origine tramite l'implementazione dell'evento di input del relativo elemento di base, può essere indirizzato mediante la parte restante della route di un evento basata su una combinazione di oggetti albero logico e struttura ad albero visuale ed essere gestito dal codice dell'applicazione. In genere, è preferibile gestire questi eventi di input correlati ai dispositivi utilizzando gli eventi indirizzati in UIElement e ContentElement, perché è possibile utilizzare una sintassi del gestore eventi più intuitiva sia in XAML che nel codice. È possibile inoltre scegliere di gestire l'evento associato che ha iniziato il processo, tuttavia potrebbero sorgere diversi problemi: l'evento associato potrebbe essere contrassegnato come gestito dalla gestione delle classi degli elementi di base, per cui potrebbe essere necessario utilizzare i metodi della funzione di accesso anziché la sintassi dell'evento vera e propria per associare i gestori per gli eventi associati.
Argomenti successivi
A questo punto si dispone di diverse tecniche per la gestione dell'input in WPF. Inoltre, si dovrebbe disporre di una conoscenza approfondita dei vari tipi di eventi di input e dei meccanismi degli eventi indirizzati utilizzati in WPF.
Sono disponibili risorse aggiuntive che illustrano più dettagliatamente gli elementi del framework WPF e il routing degli eventi. Vedere le seguenti informazioni generali: Cenni preliminari sull'esecuzione di comandi, Cenni preliminari sullo stato attivo, Cenni preliminari sugli elementi di base, informazioni generali su Strutture ad albero in WPF e Cenni preliminari sugli eventi indirizzati.
Vedere anche
Concetti
Cenni preliminari sullo stato attivo
Cenni preliminari sull'esecuzione di comandi
Cenni preliminari sugli eventi indirizzati
Cenni preliminari sugli elementi di base