Cenni preliminari sull'input
Il sottosistema Windows Presentation Foundation (WPF) fornisce un'API potente per ottenere l'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.
API di input
L'esposizione dell'API di input principale si trova nelle classi di elementi di base: UIElement, ContentElementFrameworkElement, e FrameworkContentElement. Per altre informazioni sugli elementi di base, vedere Cenni preliminari sugli elementi di base. Queste classi forniscono funzionalità per gli eventi di input correlati, ad esempio, a pressioni di tasti, pulsanti del mouse, rotellina del mouse, movimento del mouse, gestione dello stato attivo, stato mouse capture e altro. 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 KeyDown eventi e PreviewKeyDown . La differenza tra questi eventi consiste nel modo in cui ne viene eseguito il routing all'elemento di destinazione. Gli eventi di anteprima scendono lungo l'albero degli elementi (tunneling), dall'elemento radice all'elemento di destinazione. Gli eventi di bubbling invece salgono 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 Keyboard e Mouse
Oltre all'API di input nelle classi degli elementi di base, la Keyboard classe e Mouse le classi forniscono un'API aggiuntiva per l'uso dell'input tramite tastiera e mouse.
Esempi di API di input nella Keyboard classe sono la Modifiers proprietà , che restituisce l'oggetto ModifierKeys attualmente premuto e il IsKeyDown metodo , che determina se viene premuto un tasto specificato.
Nell'esempio seguente viene utilizzato il GetKeyStates metodo per determinare se un Key oggetto è nello stato 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 Mouse classe 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 l'oggetto LeftButton sul mouse si trova nello Pressed stato .
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
UpdateSampleResults("Left Button Pressed");
}
If Mouse.LeftButton = MouseButtonState.Pressed Then
UpdateSampleResults("Left Button Pressed")
End If
Le Mouse classi e Keyboard sono descritte in modo più dettagliato in questa panoramica.
Input dello stilo
WPF ha integrato il supporto per .Stylus È Stylus un input penna reso popolare dal Tablet PC. Le applicazioni WPF possono considerare lo stilo come mouse usando l'API mouse, ma WPF espone anche un'astrazione del dispositivo stilo che usa un modello simile alla tastiera e al mouse. Tutte le API correlate allo stilo contengono la parola "Stilo".
Dal momento che lo stilo può funzionare come un 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 può gestire l'evento dello stilo appropriato gestendo l'evento del mouse corrispondente. Inoltre, tramite l'astrazione del dispositivo stilo, sono disponibili anche servizi di livello superiore, come l'input penna. Per altre informazioni sull'input penna, vedere Nozioni di base sull'input penna.
Routing di eventi
Un FrameworkElement oggetto può contenere altri elementi come elementi figlio nel relativo oggetto con modalità tenda l, formando un albero di elementi. In WPF l'elemento padre può partecipare all'input diretto ai relativi elementi figlio o ad altri discendenti tramite eventi di mano. Ciò è particolarmente utile per la creazione di controlli di dimensioni inferiori, un processo noto come "composizione dei controlli" o "composizione". Per altre informazioni sugli alberi degli elementi e sul modo in cui gli alberi degli elementi sono correlati alle route degli eventi, vedere Alberi in WPF.
Il routing degli eventi è il processo di inoltro degli eventi a più elementi, in modo che un oggetto o un elemento specifico lungo la route possa offrire una risposta significativa (tramite la gestione) a un evento che potrebbe essere stato originato da un elemento diverso. Gli eventi indirizzati usano uno dei tre meccanismi di routing indicati di seguito: diretto, bubbling e tunneling. Nel routing diretto, l'elemento di origine è l'unico elemento che riceve la notifica e l'evento non viene indirizzato a nessun altro elemento. Tuttavia, l'evento indirizzato diretto offre comunque alcune funzionalità aggiuntive presenti solo per gli eventi indirizzati anziché per gli eventi CLR standard. Il bubbling viene eseguito procedendo verso l'alto nell'albero degli elementi, notificando innanzitutto l'elemento che ha originato l'evento, quindi l'elemento padre e così via. Il tunneling parte dalla radice dell'albero degli elementi e procede verso il basso, terminando con l'elemento di origine. Per altre informazioni sugli eventi indirizzati, vedere Cenni preliminari sugli eventi indirizzati.
Gli eventi di input WPF in genere sono costituiti da un evento di tunneling e da un evento di bubbling. Gli eventi di tunneling si distinguono da quelli di bubbling tramite il prefisso "Preview". Ad esempio, PreviewMouseMove è la versione di tunneling di un evento di spostamento del mouse ed 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 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 questo è semplice: fai riferimento al nome dell'evento come attributo dell'elemento che ascolterà questo evento. Si imposta quindi il valore dell'attributo sul nome del gestore eventi definito, in base a 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 azioni dei tasti eseguite quando lo stato attivo della tastiera è su un elemento. Gli eventi del mouse e dello stilo rientrano ciascuno in due categorie: eventi che segnalano modifiche nella posizione del puntatore rispetto all'elemento ed eventi che segnalano modifiche nello stato dei pulsanti del dispositivo.
Esempio di evento di input da tastiera
L'esempio seguente illustra una situazione di ascolto della pressione del tasto freccia SINISTRA. Viene StackPanel creato un oggetto con un oggetto Button. Un gestore eventi per l'ascolto della pressione del tasto freccia sinistra è collegato all'istanza Button di .
La prima sezione dell'esempio crea StackPanel e Button e associa il gestore eventi per .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 è scritta nel codice e definisce il gestore eventi. Quando viene premuto il tasto freccia sinistra e ha Button lo stato attivo della tastiera, il gestore viene eseguito e il Background colore dell'oggetto Button viene modificato. Se il tasto viene premuto, ma non è il tasto freccia sinistra, il Background colore dell'oggetto Button viene nuovamente modificato nel 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 Background colore di un Button oggetto viene modificato quando il puntatore del mouse entra in Button. Il Background colore viene ripristinato quando il mouse lascia .Button
La prima sezione dell'esempio crea e StackPanel il Button controllo e associa i gestori eventi per gli MouseEnter eventi e MouseLeave a 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 è scritta nel codice e definisce i gestori eventi. Quando il mouse entra in Button, il Background colore dell'oggetto Button viene modificato in SlateGray. Quando il mouse lascia , Buttonil Background colore dell'oggetto Button viene nuovamente modificato in 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 per l'immissione di testo, ma anche i comandi vocali, il riconoscimento della grafia e altri dispositivi di input possono generare input di testo.
Per l'input da tastiera, WPF invia prima gli eventi appropriati KeyDown/KeyUp . 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 TextInput evento. Non esiste sempre un semplice mapping uno-a-uno tra KeyDown/KeyUp gli eventi e TextInput perché più sequenze di tasti possono generare un singolo carattere di input di testo e singole sequenze di tasti possono generare stringhe a 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 KeyUp/KeyDown evento, Key è impostato su Key.System se le sequenze di tasti potrebbero diventare parte di un TextInput evento (ad esempio, se viene premuto ALT+S). In questo modo, il codice in un KeyDown gestore eventi può cercare Key.System e, se trovato, lasciare l'elaborazione per il gestore dell'evento generato TextInput 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 e ImeProcessedKey assegna la sequenza di Key.ImeProcessedtasti o le sequenze di tasti originali.
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, StackPanel riceve l'input indipendentemente dall'elemento con lo stato attivo della tastiera. Il TextBox controllo riceve prima una notifica e il OnTextInputKeyDown
gestore viene chiamato solo se l'oggetto TextBox non ha gestito l'input. Se l'evento PreviewKeyDown viene usato invece dell'evento KeyDown , il OnTextInputKeyDown
gestore viene chiamato per primo.
In questo esempio la logica di gestione viene scritta due volte, una per CTRL+O e una per l'evento Click del pulsante. È possibile semplificare questa operazione usando i comandi, invece di gestire direttamente gli eventi di input. I comandi vengono illustrati in questo articolo e in Cenni preliminari sull'esecuzione di comandi.
Tocco e manipolazione
Il nuovo hardware e le nuove API del sistema operativo Windows 7 consentono alle applicazioni di ricevere contemporaneamente input da più tocchi. 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 relativi a ogni dito appoggiato su un touchscreen e al suo movimento. Gli eventi di manipolazione interpretano l'input come azioni specifiche. Questa sezione illustra 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.
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 come 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 in più punti contemporaneamente. Windows 7 e WPF supportano il multitouch. Ogni volta che viene illustrato il tocco nella documentazione per WPF, i concetti si applicano a multitouch.
Una manipolazione si verifica quando il tocco viene interpretato come 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 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 c'è contenuto non visualizzato.
ScrollViewer Definisce la ScrollViewer.PanningMode proprietà associata che consente di specificare se la panoramica tramite tocco è abilitata orizzontalmente, verticalmente, entrambe o nessuna delle due. La ScrollViewer.PanningDeceleration proprietà specifica la velocità con cui lo scorrimento rallenta quando l'utente solleva il dito dal touchscreen. La ScrollViewer.PanningRatio proprietà associata specifica il rapporto tra offset di scorrimento e offset di manipolazione.
Eventi di tocco
Le classi di base, UIElement, UIElement3De ContentElementdefiniscono 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 rispetto alla manipolazione di un oggetto. Un'applicazione che consente a un utente di disegnare con un dito o con più dita deve ad esempio sottoscrivere gli eventi di tocco.
Tutte tre le classi definiscono gli eventi seguenti, che hanno un comportamento simile, indipendentemente dalla classe che li definisce.
Analogamente agli eventi di tastiera e 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 altre informazioni sugli eventi indirizzati, vedere Cenni preliminari sugli eventi indirizzati. Quando si gestiscono questi eventi, è possibile ottenere la posizione dell'input, rispetto a qualsiasi elemento, chiamando il GetTouchPoint metodo o GetIntermediateTouchPoints .
Per comprendere l'interazione tra gli eventi di tocco, si consideri lo scenario in cui un utente appoggia un dito su un elemento, muove il dito all'interno dell'elemento e quindi solleva il dito dall'elemento. La figura seguente illustra l'esecuzione degli eventi di bubbling. Gli eventi di tunneling vengono omessi per maggiore semplicità.
Eventi di tocco
L'elenco seguente descrive la sequenza degli eventi della figura 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 UIElement classe definisce gli eventi di manipolazione. A differenza degli eventi di tocco che segnalano semplicemente la posizione del tocco, gli eventi di manipolazione segnalano come può essere interpretato l'input. Ci sono tre tipi di manipolazioni: traslazione, espansione e rotazione. L'elenco seguente descrive come richiamare i tre tipi di manipolazioni.
Appoggiare un dito su un oggetto e muovere il dito sul touchscreen per richiamare una manipolazione di traslazione. Ciò comporta in genere lo spostamento dell'oggetto.
Appoggiare due dita su un oggetto e avvicinare o allontanare le dita tra loro per richiamare una manipolazione di espansione. Ciò comporta in genere il ridimensionamento dell'oggetto.
Appoggiare due dita su un oggetto e ruotare le dita una attorno all'altra per richiamare una manipolazione di rotazione. Ciò comporta in genere la rotazione dell'oggetto.
Si possono verificare più tipi di manipolazioni contemporaneamente.
Quando gli oggetti rispondono alle manipolazioni, si può fare in modo che sembrino avere un'inerzia. In questo modo, gli oggetti possono simulare il mondo fisico. Ad esempio se si spinge un libro su un tavolo con sufficiente forza, il libro continuerà a muoversi anche dopo che lo si lascia. 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 Procedura dettagliata: creazione della prima applicazione a tocco.
Definisce UIElement gli eventi di manipolazione seguenti.
Per impostazione predefinita, un oggetto UIElement non riceve questi eventi di manipolazione. Per ricevere eventi di manipolazione in un oggetto UIElement, impostare su UIElement.IsManipulationEnabledtrue
.
Percorso di esecuzione degli eventi di manipolazione
Si consideri uno scenario in cui un utente "lancia" un oggetto. L'utente appoggia un dito sull'oggetto, sposta 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.
La figura seguente mostra il percorso di esecuzione degli eventi di manipolazione, con informazioni importanti relative a ogni evento.
Eventi di manipolazione
L'elenco seguente descrive la sequenza degli eventi della figura precedente.
L'evento ManipulationStarting si verifica quando l'utente posiziona un dito sull'oggetto. Tra le altre cose, questo evento consente di impostare la ManipulationContainer proprietà . Negli eventi successivi, la posizione della manipolazione sarà relativa all'oggetto ManipulationContainer. Negli eventi diversi da ManipulationStarting, questa proprietà è di sola lettura, pertanto l'evento è l'unica ManipulationStarting 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 dell'utente si spostano su un touchscreen. La DeltaManipulation proprietà della ManipulationDeltaEventArgs classe indica se la manipolazione viene interpretata come movimento, espansione o traslazione. In questo contesto 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 attribuiti diversi, se si desidera. Si supponga, ad esempio, che l'applicazione includa due oggetti che rappresentano elementi nel mondo fisico e che uno di questi sia più pesante dell'altro. È possibile fare in modo che l'oggetto più pesante rallenti più velocemente rispetto a quello 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 ManipulationDeltaEventArgs.IsInertial proprietà indica se l'evento si verifica durante l'inerzia ManipulationDelta , in modo da poter controllare tale proprietà ed eseguire azioni diverse, a seconda del relativo valore.
L'evento ManipulationCompleted si verifica quando termina la manipolazione e l'inerzia. Ovvero, dopo che si verificano tutti gli ManipulationDelta eventi, l'evento ManipulationCompleted si verifica per segnalare che la manipolazione è stata completata.
Definisce UIElement anche l'evento ManipulationBoundaryFeedback . Questo evento si verifica quando il ReportBoundaryFeedback metodo 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 Window classe gestisce l'evento ManipulationBoundaryFeedback per fare in modo che la finestra venga leggermente spostata quando viene rilevato il bordo.
È possibile annullare la manipolazione chiamando il Cancel metodo sugli argomenti dell'evento in qualsiasi evento di manipolazione ad eccezione ManipulationBoundaryFeedback dell'evento. Quando si chiama Cancel, gli eventi di manipolazione non vengono più generati e si verificano eventi del mouse per il tocco. La tabella seguente descrive la relazione tra il momento in cui viene annullata la manipolazione e gli eventi del mouse che si verificano.
Evento su cui viene chiamato il metodo Cancel | Eventi del mouse che si verificano per l'input già avvenuto |
---|---|
ManipulationStarting e ManipulationStarted | Eventi di pressione del pulsante del mouse. |
ManipulationDelta | Eventi di pressione del pulsante e di spostamento del mouse. |
ManipulationInertiaStarting e ManipulationCompleted | Eventi di pressione e rilascio del pulsante e di spostamento 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 di manipolazione
Un UIElement può sempre ricevere eventi di tocco. Quando la IsManipulationEnabled proprietà è impostata su true
, un UIElement oggetto può ricevere eventi di manipolazione e tocco. Se l'evento TouchDown non viene gestito , ovvero la Handled proprietà è false
, la logica di manipolazione acquisisce il tocco all'elemento e genera gli eventi di manipolazione. Se la Handled proprietà è 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
L'elenco seguente descrive la relazione tra gli eventi di tocco e gli eventi di manipolazione illustrati nella figura precedente.
Quando il primo dispositivo virtuale genera un TouchDown evento in un UIElementoggetto , la logica di manipolazione chiama il CaptureTouch metodo , che genera l'evento GotTouchCapture .
GotTouchCapture Quando si verifica , la logica di manipolazione chiama il Manipulation.AddManipulator metodo , che genera l'evento ManipulationStarting .
Quando si verificano gli TouchMove eventi, la logica di manipolazione genera gli ManipulationDelta eventi che si verificano prima dell'evento ManipulationInertiaStarting .
Quando l'ultimo dispositivo virtuale sull'elemento genera l'evento TouchUp , la logica di manipolazione genera l'evento ManipulationInertiaStarting .
Focus
Esistono due concetti principali relativi allo stato attivo in WPF: 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 può esserci un solo elemento con lo stato attivo della tastiera. In WPF l'elemento con lo stato attivo della tastiera sarà IsKeyboardFocused impostato su true
. Il metodo FocusedElement statico Keyboard 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 .TextBox Lo stato attivo della tastiera può anche essere ottenuto a livello di codice usando il Focus metodo sulla Keyboard classe . Focus tenta di assegnare lo stato attivo della tastiera dell'elemento specificato. L'elemento restituito da Focus è l'elemento che ha attualmente lo stato attivo della tastiera.
Affinché un elemento ottenga lo stato attivo della tastiera, la Focusable proprietà e le IsVisible proprietà devono essere impostate su true. Alcune classi, ad esempio Panel, sono Focusable impostate su false
per impostazione predefinita, pertanto potrebbe essere necessario impostare questa proprietà su true
se si desidera che tale elemento sia in grado di ottenere lo stato attivo.
Nell'esempio seguente viene Focus usato per impostare lo stato attivo della tastiera su un oggetto Button. La posizione consigliata per impostare lo stato attivo iniziale in un'applicazione si trova nel Loaded gestore eventi.
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 Cenni preliminari sullo stato attivo.
Stato attivo logico
Lo stato attivo logico fa riferimento a FocusManager.FocusedElement in un ambito dello stato attivo. In un'applicazione possono esserci più elementi con lo stato attivo logico, ma in un determinato ambito di stato attivo può esserci un solo elemento con lo stato attivo logico.
Un ambito dello stato attivo è un elemento contenitore che tiene traccia dell'oggetto all'interno dell'ambito FocusedElement . 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 l'elemento con lo stato attivo in un determinato ambito rimane sicuramente tale al ritorno dello stato attivo.
Un elemento può essere trasformato in un ambito di stato attivo in XAML (Extensible Application Markup Language) impostando la FocusManager proprietà associata su true
o nel codice impostando la proprietà associata usando il SetIsFocusScopeIsFocusScope metodo .
L'esempio seguente trasforma un oggetto StackPanel in un ambito di stato attivo impostando la IsFocusScope proprietà associata.
<StackPanel Name="focusScope1"
FocusManager.IsFocusScope="True"
Height="200" Width="200">
<Button Name="button1" Height="50" Width="50"/>
<Button Name="button2" Height="50" Width="50"/>
</StackPanel>
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);
Dim focuseScope2 As New StackPanel()
FocusManager.SetIsFocusScope(focuseScope2, True)
Le classi in WPF che sono ambiti di stato attivo per impostazione predefinita sono Window, Menu, ToolBare ContextMenu.
Un elemento con lo stato attivo della tastiera avrà anche lo stato attivo logico per l'ambito dello stato attivo a cui appartiene; pertanto, impostando lo stato attivo su un elemento con il Focus metodo sulla Keyboard classe o sulle classi di elementi di base tenterà di assegnare lo stato attivo della tastiera dell'elemento e lo stato attivo logico.
Per determinare l'elemento con stato attivo in un ambito dello stato attivo, usare GetFocusedElement. Per modificare l'elemento con stato attivo per un ambito dello stato attivo, usare SetFocusedElement.
Per altre informazioni sullo stato attivo logico, vedere Cenni preliminari sullo 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)
rappresenta la coordinata superiore sinistra, ma di quale elemento dell'albero? Si tratta dell'elemento che costituisce la destinazione dell'input? O dell'elemento a cui è associato il gestore eventi? Oppure di qualche altro elemento? 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 GetPosition metodo restituisce la coordinata del puntatore del mouse rispetto all'elemento specificato.
Mouse Capture
I dispositivi di tipo mouse hanno una caratteristica modale specifica nota come mouse capture. Tale caratteristica viene usata 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, quindi la maggior parte dei segnali di passaggio del mouse risulterà inappropriata quando l'origine del trascinamento mantiene lo stato mouse capture. Il sistema di input espone api che possono determinare lo stato di acquisizione del mouse, nonché API che possono forzare l'acquisizione del mouse in un elemento specifico o cancellare lo stato di acquisizione del mouse. Per altre informazioni sulle operazioni di trascinamento della selezione, vedere Cenni preliminari sul trascinamento della selezione.
Comandi
I comandi consentono la gestione dell'input a un livello più semantico rispetto all'input dei dispositivi. I comandi sono semplici direttive, come Cut
, Copy
, Paste
o Open
. I comandi sono utili per centralizzare la logica di comando. È possibile accedere allo stesso comando da un oggetto , in un MenuToolBaroggetto o 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 un oggetto RoutedCommand viene eseguito, viene generato un PreviewExecuted oggetto e un Executed evento sulla destinazione del comando, che esegue il tunneling e la bolla attraverso l'albero degli elementi come l'altro input. Se non è impostata una destinazione del comando, questa sarà rappresentata dall'elemento con lo stato attivo della tastiera. La logica che esegue il comando è collegata a un oggetto CommandBinding. Quando un Executed evento raggiunge un CommandBinding oggetto per tale comando specifico, viene chiamato su CommandBindingExecutedRoutedEventHandler . Il gestore esegue l'azione del comando.
Per altre informazioni sui comandi, vedere Cenni preliminari sull'esecuzione di comandi.
WPF offre una libreria di comandi comuni costituiti da ApplicationCommands, MediaCommands, ComponentCommandsNavigationCommands, e EditingCommandsoppure è possibile definire i propri comandi.
Nell'esempio seguente viene illustrato come configurare un oggetto MenuItem in modo che, quando viene fatto clic, richiamerà il Paste comando su TextBox, presupponendo che abbia TextBox lo stato attivo 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 Cenni preliminari sul comando.
Sistema di input ed elementi di base
Gli eventi di input, ad esempio gli eventi associati definiti dalle Mouseclassi , Keyboarde Stylus , vengono generati dal sistema di input e inseriti in una particolare posizione nel modello a oggetti in base all'hit testing della struttura ad albero visuale in fase di esecuzione.
Ogni evento che Mouse, Keyboarde Stylus definiscono come evento associato viene esposto nuovamente dalle classi UIElement di elementi di base e ContentElement come nuovo evento indirizzato. Gli eventi indirizzati degli elementi di base vengono generati da classi che gestiscono l'evento associato 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 dei relativi elementi di base, può essere indirizzato lungo 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, è più pratico gestire questi eventi di input correlati al dispositivo usando gli eventi indirizzati su UIElement e ContentElement, perché è possibile usare la sintassi del gestore eventi più intuitiva sia in XAML che nel codice. È possibile scegliere di gestire invece l'evento associato che ha avviato il processo, ma potrebbero sorgere diversi problemi: l'evento associato potrebbe essere contrassegnato come gestito dalla gestione della classe dell'elemento di base, per cui potrebbe essere necessario usare i metodi della funzione di accesso invece della sintassi dell'evento vera e propria per associare i gestori per gli eventi associati.
E adesso
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 generali, vedere Cenni preliminari sull'esecuzione di comandi, Cenni preliminari sullo stato attivo, Cenni preliminari sugli elementi di base, Strutture ad albero in WPF e Cenni preliminari sugli eventi indirizzati.
Vedi anche
.NET Desktop feedback