Panoramica dell'input
il sottosistema Windows Presentation Foundation (WPF) offre un'API potente per ottenere input da un'ampia gamma di dispositivi, tra cui mouse, tastiera, tocco e stilo. In questo argomento vengono descritti i servizi forniti da WPF e viene illustrata l'architettura dei sistemi di input.
Input API
L'esposizione dell'API di input principale si trova nelle classi di elementi di base: UIElement, ContentElement, FrameworkElemente FrameworkContentElement. Per altre informazioni sugli elementi di base, vedere panoramica degli elementi di base . Queste classi forniscono funzionalità per gli eventi di input correlati ai tasti premuti, ai pulsanti del mouse, alla rotellina del mouse, allo spostamento del mouse, alla gestione dello stato del focus e all'acquisizione del mouse, per citarne alcuni. Inserendo l'API di input sugli elementi di base, invece di considerare tutti gli eventi di input come servizio, l'architettura di input consente l'origine degli eventi di input da un determinato oggetto nell'interfaccia utente e per supportare uno schema di routing degli eventi in cui più di un elemento ha la possibilità di gestire un evento di input. A molti eventi di input è associata una coppia di eventi. Ad esempio, l'evento key down è associato agli eventi KeyDown e PreviewKeyDown. La differenza in questi eventi consiste nel modo in cui vengono indirizzati all'elemento di destinazione. Gli eventi di anteprima tunnelizzano nell'albero degli elementi dall'elemento radice all'elemento di destinazione. Gli eventi bubbling si propagano dall'elemento di destinazione all'elemento radice. Il routing degli eventi in WPF viene illustrato in modo più dettagliato più avanti in questa panoramica e nella panoramica degli eventi indirizzati .
Classi di tastiera e mouse
Oltre all'API di input nelle classi degli elementi di base, la classe Keyboard e le classi Mouse forniscono API aggiuntive per l'uso dell'input tramite tastiera e mouse.
Esempi di API di input nella classe Keyboard sono la proprietà Modifiers, che restituisce il ModifierKeys attualmente premuto e il metodo IsKeyDown, che determina se viene premuto un tasto specificato.
Nell'esempio seguente viene utilizzato il metodo GetKeyStates per determinare se un Key è inattivo.
// 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;
}
' 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
Esempi di API di input nella classe Mouse sono MiddleButton, che ottiene lo stato del pulsante centrale del mouse e DirectlyOver, che ottiene l'elemento su cui è attualmente posizionato il puntatore del mouse.
Nell'esempio seguente viene determinato se il LeftButton sul mouse si trova nello stato Pressed.
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
UpdateSampleResults("Left Button Pressed");
}
If Mouse.LeftButton = MouseButtonState.Pressed Then
UpdateSampleResults("Left Button Pressed")
End If
Le classi Mouse e Keyboard sono descritte in modo più dettagliato in questa panoramica.
Input dello stilo
WPF ha integrato il supporto per il Stylus. Il Stylus è un input con penna reso popolare dai Tablet PC. Le applicazioni WPF possono trattare lo stilo come un mouse utilizzando l'API del mouse, ma WPF espone anche un'astrazione del dispositivo stilo che utilizza un modello simile alla tastiera e al mouse. Tutte le API correlate allo stilo contengono la parola "Stylus".
Poiché lo stilo può fungere da mouse, le applicazioni che supportano solo l'input del mouse possono comunque ottenere automaticamente un certo livello di supporto dello stilo. Quando lo stilo viene usato in questo modo, l'applicazione ha la possibilità di gestire l'evento dello stilo appropriato e quindi gestisce l'evento del mouse corrispondente. Inoltre, servizi di livello superiore, come l'input di inchiostro, sono disponibili anche tramite l'astrazione del dispositivo stilo. Per ulteriori informazioni sull'uso dell'inchiostro, vedere Introduzione all'inchiostro.
Instradamento degli eventi
Un FrameworkElement può contenere altri elementi come elementi figli nel modello di contenuto, formando un albero di elementi. In WPF, l'elemento padre può partecipare all'input diretto ai relativi elementi figlio o ad altri discendenti gestendo gli eventi. Ciò è particolarmente utile per costruire nuovi controlli utilizzando controlli più piccoli, un processo noto come "composizione dei controlli" o "composizione". Per ulteriori informazioni sugli alberi degli elementi e su come sono correlati alle route degli eventi, vedere Trees in WPF.
Il routing degli eventi è il processo di inoltro di eventi a più elementi, in modo che un particolare oggetto o elemento lungo il percorso possa scegliere di offrire una risposta significativa (attraverso la gestione) a un evento che potrebbe essere stato originato da un elemento diverso. Gli eventi indirizzati usano uno dei tre meccanismi di routing: direct, bubbling e tunneling. Nel routing diretto, l'elemento di origine è l'unico elemento che riceve una notifica e l'evento non viene instradato ad altri elementi. Tuttavia, l'evento indirizzato diretto offre comunque alcune funzionalità aggiuntive presenti solo per gli eventi indirizzati anziché per gli eventi CLR standard. Bubbling funziona risalendo l'albero degli elementi notificando prima l'elemento che ha originato l'evento, poi l'elemento padre e così via. Il tunneling inizia alla radice dell'albero degli elementi e funziona verso il basso, terminando con l'elemento di origine originale. Per altre informazioni sugli eventi indirizzati, vedere Panoramica degli eventi indirizzati.
Gli eventi di input WPF generalmente vengono in coppia, costituiti da un evento di tunneling e un evento di bubbling. Gli eventi di tunneling si distinguono dagli eventi di bubbling con il prefisso "Preview". Ad esempio, PreviewMouseMove è la versione di tunneling di un evento di spostamento del mouse e MouseMove è la versione di bubbling di questo evento. Questa associazione di eventi è una convenzione implementata a livello di elemento e non è una funzionalità intrinseca del sistema di eventi WPF. Per informazioni dettagliate, vedere la sezione Eventi di input WPF in Panoramica degli Eventi di Routing.
Gestione degli eventi di input
Per ricevere l'input su un elemento, un gestore eventi deve essere associato a tale evento specifico. In XAML questo è semplice: fai riferimento al nome dell'evento come attributo dell'elemento che ascolterà questo evento. Imposti quindi il valore dell'attributo sul nome del gestore eventi che definisci, sulla base di un delegato. Il gestore eventi deve essere scritto nel codice, ad esempio C# e può essere incluso in un file code-behind.
Gli eventi della tastiera si verificano quando il sistema operativo segnala le azioni chiave che si verificano mentre lo stato attivo della tastiera si trova su un elemento. Gli eventi del mouse e dello stilo rientrano in due categorie: eventi che segnalano modifiche nella posizione del puntatore rispetto all'elemento e eventi che segnalano modifiche allo stato dei pulsanti del dispositivo.
Esempio di evento di input da tastiera
Nell'esempio seguente si rileva la pressione del tasto freccia sinistra. Si crea un StackPanel che ha un Button. Un gestore di eventi per rilevare la pressione del tasto freccia sinistra è collegato all'istanza Button.
La prima sezione dell'esempio crea il StackPanel e il Button e associa il gestore eventi per il KeyDown.
<StackPanel>
<Button Background="AliceBlue"
KeyDown="OnButtonKeyDown"
Content="Button1"/>
</StackPanel>
// 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);
' 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
La seconda sezione viene scritta nel codice e definisce il gestore eventi. Quando si preme il tasto freccia sinistra e la Button ha il focus della tastiera, il gestore viene eseguito e il colore Background del Button viene modificato. Se il tasto viene premuto, ma non è il tasto freccia sinistra, il colore Background del Button viene nuovamente impostato sul colore iniziale.
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;
}
}
}
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
Esempio di evento di input del mouse
Nell'esempio seguente, il colore Background di un Button viene modificato quando il puntatore del mouse entra nel Button. Il colore Background viene ripristinato quando il mouse lascia il Button.
La prima sezione dell'esempio crea il StackPanel e il controllo Button e associa i gestori eventi per gli eventi MouseEnter e MouseLeave al Button.
<StackPanel>
<Button Background="AliceBlue"
MouseEnter="OnMouseExampleMouseEnter"
MouseLeave="OnMosueExampleMouseLeave">Button
</Button>
</StackPanel>
// 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);
' 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
La seconda sezione dell'esempio viene scritta nel codice e definisce i gestori eventi. Quando il mouse entra nel Button, il colore Background del Button viene modificato in SlateGray. Quando il mouse lascia il Button, il colore Background del Button viene nuovamente impostato su AliceBlue.
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 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 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;
}
}
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
Input di testo
L'evento TextInput consente di ascoltare l'input di testo in modo indipendente dal dispositivo. La tastiera è il mezzo principale dell'input di testo, ma anche il riconoscimento vocale, la grafia e altri dispositivi di input possono generare input di testo.
Per l'input da tastiera, WPF invia innanzitutto gli eventi di KeyDown/KeyUp appropriati. Se tali eventi non vengono gestiti e la chiave è testuale (anziché un tasto di controllo, ad esempio frecce direzionali o tasti funzione), viene generato un evento TextInput. Non esiste sempre una semplice corrispondenza uno-a-uno tra gli eventi KeyDown/KeyUp e TextInput perché più pressioni di tasti possono generare un singolo carattere di input di testo e singole pressioni di tasti possono generare stringhe di più caratteri. Ciò vale soprattutto per le lingue come cinese, giapponese e coreano che usano input method editor (IMEs) per generare le migliaia di caratteri possibili negli alfabeti corrispondenti.
Quando WPF invia un evento KeyUp/KeyDown, Key è impostato su Key.System se le sequenze di tasti potrebbero far parte di un evento TextInput (ad esempio, se viene premuto ALT+S). In questo modo, il codice in un gestore eventi KeyDown può verificare la presenza di Key.System e, qualora presente, delegare l'elaborazione al gestore dell'evento TextInput generato successivamente. In questi casi, è possibile utilizzare le varie proprietà dell'argomento TextCompositionEventArgs per determinare le sequenze di tasti originali. Analogamente, se un IME è attivo, Key ha il valore di Key.ImeProcessede ImeProcessedKey fornisce la sequenza di tasti originale.
Nell'esempio seguente viene definito un gestore per l'evento Click e un gestore per l'evento KeyDown.
Il primo segmento di codice o markup crea l'interfaccia utente.
<StackPanel KeyDown="OnTextInputKeyDown">
<Button Click="OnTextInputButtonClick"
Content="Open" />
<TextBox> . . . </TextBox>
</StackPanel>
// 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);
' 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
Il secondo segmento di codice contiene i gestori eventi.
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");
}
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
Poiché gli eventi di input si spostano verso l'alto nella route degli eventi, il StackPanel riceve l'input indipendentemente dall'elemento con lo stato attivo della tastiera. Il controllo TextBox viene avvisato per primo e il gestore OnTextInputKeyDown
viene chiamato solo se il TextBox non ha gestito l'input. Se l'evento PreviewKeyDown viene utilizzato invece dell'evento KeyDown, viene chiamato prima il gestore OnTextInputKeyDown
.
In questo esempio la logica di gestione viene scritta due volte, una volta per CTRL+O e di nuovo per l'evento click del pulsante. Questa operazione può essere semplificata usando i comandi, invece di gestire direttamente gli eventi di input. I comandi vengono discussi in questa panoramica e in Panoramica dei Comandi.
Tocco e manipolazione
La nuova api e l'hardware nel sistema operativo Windows 7 offrono alle applicazioni la possibilità di ricevere l'input da più touch contemporaneamente. WPF consente alle applicazioni di rilevare e rispondere al tocco in modo simile alla risposta ad altri input, ad esempio il mouse o la tastiera, generando eventi quando si verifica il tocco.
WPF espone due tipi di eventi quando si verifica il tocco: eventi di tocco ed eventi di manipolazione. Gli eventi di tocco forniscono dati non elaborati su ogni dito su un touchscreen e sul relativo movimento. Gli eventi di manipolazione interpretano l'input come determinate azioni. In questa sezione vengono illustrati entrambi i tipi di eventi.
Prerequisiti
Per sviluppare un'applicazione che risponde al tocco, sono necessari i componenti seguenti.
Visual Studio 2010.
Windows 7.
Un dispositivo, ad esempio un touchscreen, che supporta Windows Touch.
Terminologia
Quando si parla di tocco, vengono usati i termini seguenti.
Touch è un tipo di input utente riconosciuto da Windows 7. In genere, il tocco viene avviato mettendo le dita su uno schermo sensibile al tocco. Si noti che i dispositivi come un touchpad comune nei computer portatili non supportano il tocco se il dispositivo converte semplicemente la posizione e il movimento del dito come input del mouse.
Multitouch è un tocco che si verifica da più di un punto contemporaneamente. Windows 7 e WPF supportano il multitouch. Ogni volta che viene illustrata l'interazione tattile nella documentazione relativamente a WPF, i concetti si applicano al multitouch.
Una manipolazione si verifica quando il tocco viene interpretato come un'azione fisica applicata a un oggetto. In WPF gli eventi di manipolazione interpretano l'input come traslazione, espansione o manipolazione della rotazione.
Un
touch device
rappresenta un dispositivo che produce input tattile, come un singolo dito su un touchscreen.
Controlli che rispondono al tocco
È possibile scorrere i controlli seguenti trascinando un dito sul controllo, se quest'ultimo ha contenuto che non è visibile.
Il ScrollViewer definisce la proprietà associata ScrollViewer.PanningMode che consente di specificare se lo scorrimento tramite tocco è abilitato orizzontalmente, verticalmente, in entrambi i casi o in nessuno. La proprietà ScrollViewer.PanningDeceleration specifica la velocità con cui lo scorrimento rallenta quando l'utente solleva il dito dal touchscreen. La proprietà associata ScrollViewer.PanningRatio specifica il rapporto tra offset di scorrimento e offset di manipolazione.
Eventi tattili
Le classi di base, UIElement, UIElement3De ContentElement, definiscono gli eventi che è possibile sottoscrivere in modo che l'applicazione risponda al tocco. Gli eventi di tocco sono utili quando l'applicazione interpreta il tocco come qualcosa di diverso dalla modifica di un oggetto. Ad esempio, un'applicazione che consente a un utente di disegnare con una o più dita sottoscrive gli eventi di tocco.
Tutte e tre le classi definiscono gli eventi seguenti, che si comportano in modo analogo, indipendentemente dalla classe di definizione.
Come gli eventi della tastiera e del mouse, gli eventi di 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 sui routed events, vedere Panoramica dei routed events. Quando si gestiscono questi eventi, è possibile ottenere la posizione dell'input, rispetto a qualsiasi elemento, chiamando il metodo GetTouchPoint o GetIntermediateTouchPoints.
Per comprendere l'interazione tra gli eventi di tocco, considerare lo scenario in cui un utente posiziona un dito su un elemento, sposta il dito nell'elemento e quindi solleva il dito dall'elemento. La figura seguente mostra l'esecuzione degli eventi di bubbling (gli eventi di tunneling vengono omessi per semplicità).
Nell'elenco seguente viene descritta la sequenza degli eventi nell'illustrazione precedente.
L'evento TouchEnter si verifica una volta quando l'utente posiziona un dito sull'elemento.
L'evento TouchDown si verifica una volta.
L'evento TouchMove si verifica più volte quando l'utente sposta 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.
Quando vengono usate più di due dita, gli eventi si verificano per ogni dito.
Eventi di manipolazione
Nei casi in cui un'applicazione consente a un utente di modificare un oggetto, la classe UIElement definisce gli eventi di manipolazione. A differenza degli eventi di tocco che segnalano semplicemente la posizione del tocco, gli eventi di manipolazione segnalano come l'input può essere interpretato. Esistono tre tipi di manipolazioni, traslazione, espansione e rotazione. Nell'elenco seguente viene descritto come richiamare i tre tipi di manipolazioni.
Posizionare un dito su un oggetto e spostare il dito attraverso il touchscreen per richiamare una manipolazione della traduzione. In genere, l'oggetto viene spostato.
Metti due dita su un oggetto e sposta le dita più vicine o più lontane l'una dall'altra per richiamare una manipolazione di espansione. In genere l'oggetto viene ridimensionato.
Posizionare due dita su un oggetto e ruotare le dita l'una attorno all'altra per richiamare una manipolazione di rotazione. In genere l'oggetto viene ruotato.
Più tipi di manipolazione possono verificarsi contemporaneamente.
Quando si fa in modo che gli oggetti rispondano alle manipolazioni, è possibile che l'oggetto abbia un'inerzia. In questo modo gli oggetti possono simulare il mondo fisico. Ad esempio, quando si spinge un libro su un tavolo, se si spinge abbastanza forte, il libro continuerà a muoversi dopo che lo hai lasciato. WPF consente di simulare questo comportamento generando eventi di manipolazione dopo che le dita dell'utente rilasciano l'oggetto.
Per informazioni su come creare un'applicazione che consente all'utente di spostare, ridimensionare e ruotare un oggetto, vedere Guida: Creazione della tua prima applicazione touch.
Il UIElement definisce gli eventi di manipolazione seguenti.
Per impostazione predefinita, un UIElement non riceve questi eventi di manipolazione. Per ricevere eventi di manipolazione su UIElement, impostare UIElement.IsManipulationEnabled su true
.
Percorso di esecuzione degli eventi di manipolazione
Si consideri uno scenario in cui un utente "lancia" un oggetto. L'utente posiziona un dito sull'oggetto, sposta il dito sul touchscreen per una breve distanza e quindi solleva il dito mentre si muove. Il risultato è che l'oggetto si muoverà sotto il dito dell'utente e continuerà a muoversi dopo che l'utente solleva il dito.
La figura seguente mostra il percorso di esecuzione degli eventi di manipolazione e informazioni importanti su ogni evento.
Eventi di manipolazione.
Nell'elenco seguente viene descritta la sequenza degli eventi nell'illustrazione precedente.
L'evento ManipulationStarting si verifica quando l'utente posiziona un dito sull'oggetto. Tra le altre cose, questo evento consente di impostare la proprietà ManipulationContainer. Negli eventi successivi, la posizione della manipolazione sarà relativa alla ManipulationContainer. Negli eventi diversi da ManipulationStarting, questa proprietà è di sola lettura, pertanto l'evento ManipulationStarting è l'unica volta che è possibile impostare questa proprietà.
L'evento ManipulationStarted si verifica successivamente. Questo evento segnala l'origine della manipolazione.
L'evento ManipulationDelta si verifica più volte quando le dita di un utente si spostano su un touchscreen. La proprietà DeltaManipulation della classe ManipulationDeltaEventArgs indica se la manipolazione viene interpretata come movimento, espansione o traslazione. Qui si esegue la maggior parte del lavoro di manipolazione di un oggetto.
L'evento ManipulationInertiaStarting si verifica quando le dita dell'utente perdono il contatto con l'oggetto. Questo evento consente di specificare la decelerazione delle manipolazioni durante l'inerzia. In questo modo l'oggetto può emulare spazi fisici o attributi diversi, se si sceglie. Si supponga, ad esempio, che l'applicazione abbia due oggetti che rappresentano elementi nel mondo fisico e uno è più pesante dell'altro. È possibile velocizzare la decelerazione dell'oggetto più pesante rispetto all'oggetto più leggero.
L'evento ManipulationDelta si verifica più volte quando si verifica l'inerzia. Si noti che questo evento si verifica quando le dita dell'utente si spostano sul touchscreen e quando WPF simula l'inerzia. In altre parole, ManipulationDelta si verifica prima e dopo l'evento ManipulationInertiaStarting. La proprietà ManipulationDeltaEventArgs.IsInertial indica se l'evento ManipulationDelta si verifica durante l'inerzia, in modo da poter controllare tale proprietà ed eseguire azioni diverse, a seconda del relativo valore.
L'evento ManipulationCompleted si verifica quando la manipolazione e l'inerzia sono finite. Ovvero, dopo che si verificano tutti gli eventi ManipulationDelta, l'evento ManipulationCompleted si verifica per segnalare che la manipolazione è stata completata.
Il UIElement definisce anche l'evento ManipulationBoundaryFeedback. Questo evento si verifica quando il metodo ReportBoundaryFeedback viene chiamato nell'evento ManipulationDelta. L'evento ManipulationBoundaryFeedback consente alle applicazioni o ai componenti di fornire feedback visivo quando un oggetto raggiunge un limite. Ad esempio, la classe Window gestisce l'evento ManipulationBoundaryFeedback per far sì che la finestra si sposti leggermente quando viene rilevato il bordo.
È possibile annullare la manipolazione chiamando il metodo Cancel sugli argomenti dell'evento, in un qualsiasi evento di manipolazione, tranne l'evento ManipulationBoundaryFeedback. Quando si invoca Cancel, gli eventi di gestione non vengono più generati e gli eventi del mouse si verificano per l’interazione touch. Nella tabella seguente viene descritta la relazione tra il momento in cui la manipolazione viene annullata e gli eventi del mouse che si verificano.
Evento in cui viene chiamato Cancel | Gli eventi del mouse che si verificano per un input già avvenuto |
---|---|
ManipulationStarting e ManipulationStarted | Eventi di scorrimento del mouse. |
ManipulationDelta | Eventi di click del mouse e movimento del mouse. |
ManipulationInertiaStarting e ManipulationCompleted | Eventi di pressione, movimento e rilascio del mouse. |
Si noti che se si chiama Cancel quando la manipolazione è in inerzia, il metodo restituisce false
e l'input non genera eventi del mouse.
Relazione tra eventi di tocco e manipolazione
Un UIElement può sempre ricevere eventi di tocco. Quando la proprietà IsManipulationEnabled è impostata su true
, un UIElement può ricevere eventi di tocco e manipolazione. Se l'evento TouchDown non viene gestito ( ovvero la proprietà Handled è false
), la logica di manipolazione acquisisce il tocco all'elemento e genera gli eventi di manipolazione. Se la proprietà Handled è impostata su true
nell'evento TouchDown, la logica di manipolazione non genera eventi di manipolazione. La figura seguente mostra la relazione tra eventi di tocco ed eventi di manipolazione.
eventi di tocco e manipolazione
Nell'elenco seguente viene descritta la relazione tra gli eventi di tocco e manipolazione illustrati nella figura precedente.
Quando il primo dispositivo tattile genera un evento TouchDown in un UIElement, la logica di manipolazione chiama il metodo CaptureTouch, che genera l'evento GotTouchCapture.
Quando si verifica la GotTouchCapture, la logica di manipolazione chiama il metodo Manipulation.AddManipulator, che genera l'evento ManipulationStarting.
Quando si verificano gli eventi di TouchMove, la logica di manipolazione genera gli eventi ManipulationDelta che si verificano prima dell'evento ManipulationInertiaStarting.
Quando l'ultimo dispositivo touch sull'elemento genera l'evento TouchUp, la logica di manipolazione genera l'evento ManipulationInertiaStarting.
Focus
Esistono due concetti principali riguardanti lo stato attivo in WPF: lo stato attivo della tastiera e lo stato attivo logico.
Messa a fuoco della tastiera
Il focus della tastiera si riferisce all'elemento che riceve l'input da tastiera. L'intero desktop può contenere un solo elemento con lo stato attivo della tastiera. In WPF l'elemento con stato attivo della tastiera avrà IsKeyboardFocused impostato su true
. Il metodo statico KeyboardFocusedElement restituisce l'elemento che ha attualmente lo stato attivo della tastiera.
Lo stato attivo della tastiera può essere ottenuto tramite tabulazione su un elemento o facendo clic sul mouse su determinati elementi, ad esempio un TextBox. Lo stato attivo della tastiera può essere ottenuto anche programmaticamente usando il metodo Focus nella classe Keyboard. Focus tenta di dare all'elemento specificato il focus della tastiera. L'elemento restituito da Focus è l'elemento che attualmente ha lo stato attivo della tastiera.
Affinché un elemento ottenga lo stato attivo della tastiera, le proprietà Focusable e IsVisible devono essere impostate su true. Alcune classi, ad esempio Panel, hanno Focusable impostato su false
di default; quindi, potrebbe essere necessario impostare questa proprietà su true
se si desidera che tale elemento possa ricevere il focus.
L'esempio seguente usa Focus per mettere a fuoco la tastiera su un Button. La posizione consigliata per impostare lo stato attivo iniziale in un'applicazione si trova nel gestore eventi Loaded.
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
Per altre informazioni sullo stato attivo della tastiera, vedere Panoramica dello stato attivo.
Focus Logico
Lo stato attivo logico fa riferimento al FocusManager.FocusedElement in un ambito dello stato attivo. 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 ambito di messa a fuoco è un elemento contenitore che tiene traccia delle FocusedElement all'interno del proprio ambito. Quando il focus lascia un ambito di riferimento, l'elemento che aveva il focus sulla tastiera lo perderà ma manterrà il focus logico. Quando il focus ritorna all'ambito del focus, l'elemento in questione riceverà il focus dalla tastiera. Ciò consente di cambiare il focus della tastiera tra diversi ambiti di focalizzazione, garantendo che l'elemento focalizzato all'interno dell'ambito di focalizzazione rimanga tale quando il focus viene ripristinato.
Un elemento può essere trasformato in un ambito di focus in XAML (Extensible Application Markup Language) impostando la proprietà associata FocusManagerIsFocusScope su true
o nel codice impostando la proprietà associata usando il metodo SetIsFocusScope.
L'esempio seguente trasforma 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)
Le classi in WPF che sono ambiti di focus per impostazione predefinita sono Window, Menu, ToolBare ContextMenu.
Un elemento che ha il fuoco della tastiera avrà anche il fuoco logico per l'ambito di appartenenza; pertanto, impostare il fuoco su un elemento utilizzando il metodo Focus sulla classe Keyboard o sulle classi base tenterà di assegnare a quell'elemento sia il fuoco della tastiera che il fuoco logico.
Per determinare l'elemento a fuoco in un ambito di messa a fuoco, usare GetFocusedElement. Per modificare l'elemento a cui è assegnato lo stato attivo per un contesto dello stato attivo, usare SetFocusedElement.
Per altre informazioni sullo stato attivo logico, vedere panoramica dello stato attivo .
Posizione del mouse
L'API di input WPF fornisce informazioni utili per quanto riguarda gli spazi di coordinate. Ad esempio, la coordinata (0,0)
è la coordinata in alto a sinistra, ma in alto a sinistra di quale elemento nell'albero? Qual è l'elemento che è il bersaglio dell'input? L'elemento a cui hai collegato il gestore dell'evento? O qualcos'altro? Per evitare confusione, l'API di input WPF richiede di specificare il frame di riferimento quando si lavora con le coordinate ottenute tramite il mouse. Il metodo GetPosition restituisce la coordinata del puntatore del mouse rispetto all'elemento specificato.
Acquisizione mouse
I dispositivi mouse contengono in modo specifico una caratteristica modale nota come acquisizione del mouse. L'acquisizione del controllo del mouse viene utilizzata per mantenere uno stato di input transitorio quando viene avviata un'operazione di trascinamento e rilascio, in modo che altre operazioni che coinvolgono la posizione nominale sullo schermo del puntatore non si verificano necessariamente. Durante il trascinamento e rilascio, l'utente non può fare clic senza interrompere l'operazione, il che rende la maggior parte degli indicatori del mouse inappropriati mentre il mouse è bloccato dall'origine del trascinamento. Il sistema di input espone API che possono determinare lo stato di acquisizione del mouse, nonché API che possono forzare l'acquisizione del mouse su un elemento specifico o cancellare lo stato di acquisizione del mouse. Per ulteriori informazioni sulle operazioni di trascina e rilascia, vedere Panoramica del trascinamento e rilascio.
Comandi
I comandi consentono la gestione dell'input a un livello più semantico rispetto all'input del dispositivo. I comandi sono direttive semplici, ad esempio Cut
, Copy
, Paste
o Open
. I comandi sono utili per centralizzare la logica dei comandi. È possibile accedere allo stesso comando da un Menu, in un ToolBaro tramite una scelta rapida da tastiera. I comandi forniscono anche un meccanismo per disabilitare i controlli quando il comando non è più disponibile.
RoutedCommand è l'implementazione WPF di ICommand. Quando viene eseguito un RoutedCommand, vengono generati un evento PreviewExecuted e un evento Executed sulla destinazione del comando, che eseguono il tunneling e il bubbling attraverso l'albero degli elementi come gli altri input. Se non è impostata una destinazione del comando, la destinazione sarà l'elemento che ha il focus della tastiera. La logica che esegue il comando è collegata a un CommandBinding. Quando un evento Executed raggiunge un CommandBinding per quel comando specifico, viene chiamato il ExecutedRoutedEventHandler sul CommandBinding. Questo gestore esegue l'azione del comando .
Per altre informazioni sui comandi, vedere Panoramica dei comandi.
WPF offre una libreria di comandi comuni costituiti da ApplicationCommands, MediaCommands, ComponentCommands, NavigationCommandse EditingCommandsoppure è possibile definire i propri.
Nell'esempio seguente viene illustrato come configurare un MenuItem in modo che, quando viene cliccato, richiamerà il comando Paste sul TextBox, presupponendo che il TextBox abbia il fuoco della tastiera.
<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste" />
</Menu>
<TextBox />
</StackPanel>
// 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;
' 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
Per altre informazioni sui comandi in WPF, vedere Panoramica dell'esecuzione di comandi.
Il sistema di input e gli elementi di base
Gli eventi di input, come ad esempio gli eventi associati definiti dalle classi Mouse, Keyboarde Stylus, vengono generati dal sistema di input e inseriti in una posizione specifica nel modello di oggetti in base al test di collisione dell'albero visivo durante il runtime.
Ogni evento definito come evento associato da Mouse, Keyboarde Stylus è anche ri-esposto dalle classi base di elementi UIElement e ContentElement come nuovo evento instradato. Gli eventi indirizzati dell'elemento base vengono generati dalle classi che gestiscono l'evento allegato originale e riutilizzano i dati dell'evento.
Quando l'evento di input viene associato a un particolare elemento di origine tramite l'implementazione dell'evento di input dell'elemento di base, può essere indirizzato attraverso il resto di un percorso di eventi basato su una combinazione di oggetti dell'albero logico e visivo, e gestito tramite il codice dell'applicazione. In genere, è più pratico gestire questi eventi di input correlati al dispositivo usando gli eventi indirizzati su UIElement e ContentElement, perché è possibile usare una sintassi del gestore eventi più intuitiva sia in XAML che nel codice. È possibile scegliere di gestire l'evento associato che ha avviato il processo, ma si riscontrano diversi problemi: l'evento associato può essere contrassegnato come gestito dalla classe dell'elemento di base, e dovrai utilizzare metodi accessor anziché la sintassi di evento vera e propria per allegare gestori agli eventi associati.
Cosa ci aspetta
Sono ora disponibili diverse tecniche per gestire l'input in WPF. È anche necessario avere una migliore comprensione dei vari tipi di eventi di input e dei meccanismi degli eventi indirizzati usati da WPF.
Sono disponibili risorse aggiuntive che illustrano in modo più dettagliato gli elementi del framework WPF e il routing degli eventi. Per altre informazioni, vedere le panoramiche seguenti Panoramica dei comandi, panoramica dello stato attivo , Panoramica degli elementi di base, alberi in WPFe panoramica degli eventi indirizzati .
Vedere anche
- Panoramica del focus
- Panoramica dei Comandi
- Panoramica degli eventi instradati
- Panoramica Elementi di Base
- Proprietà
.NET Desktop feedback