Condividi tramite


Gestire l'input del puntatore

Ricevere, elaborare e gestire dati di input dai dispositivi di puntamento (ad esempio il tocco, il mouse, la penna e il touchpad) nelle applicazioni Windows.

Importante

Creare interazioni personalizzate solo se esiste un requisito chiaro e ben definito e le interazioni supportate dai controlli della piattaforma non supportano lo scenario.
Se si personalizzano le esperienze di interazione nell'applicazione Windows, gli utenti si aspettano che siano coerenti, intuitivi e individuabili. Per questi motivi, è consigliabile modellare le interazioni personalizzate su quelle supportate dai controlli della piattaforma . I controlli della piattaforma offrono l'esperienza di interazione utente completa dell'app Di Windows, incluse interazioni standard, effetti fisici animati, feedback visivo e accessibilità.

API importanti

Puntatori

La maggior parte delle esperienze di interazione utente implica in genere che l'utente identifichi l'oggetto con cui vuole interagire indicandolo attraverso dispositivi di input come touchscreen, mouse, penna/stilo e touchpad. Poiché i dati HID (Human Interface Device) non elaborati forniti da questi dispositivi di input includono molte proprietà comuni, vengono consolidati e promossi in un unico stack di input ed esposti come dati di puntatore indipendenti dai dispositivi. Le applicazioni Windows possono quindi utilizzare questi dati senza preoccuparsi del dispositivo di input in uso.

Annotazioni

Le informazioni specifiche del dispositivo sono anche ricavate dai dati grezzi HID, se l'applicazione lo richiede.

Ogni punto di input (o contatto) nello stack di input è rappresentato da un oggetto puntatore esposto tramite il parametro PointerRoutedEventArgs nei vari gestori degli eventi del puntatore. Nel caso di input multipenna o multitocco, ogni contatto viene considerato come un puntatore input univoco.

Eventi puntatore

Gli eventi del puntatore forniscono informazioni di base, come il tipo di dispositivo di input e lo stato di rilevamento (a portata o a contatto), e informazioni estese come la posizione, la pressione e la geometria del contatto. Inoltre, sono disponibili proprietà specifiche del dispositivo, come ad esempio quale pulsante del mouse un utente ha premuto o se è in uso la punta della gomma della penna. Se l'app deve distinguere tra i dispositivi di input e le relative funzionalità, vedere Identificare i dispositivi di input.

Le app di Windows possono restare in ascolto degli eventi puntatore seguenti:

Annotazioni

Vincola l'input del puntatore a un elemento specifico dell'interfaccia utente chiamando CapturePointer su tale elemento all'interno di un gestore di eventi del puntatore. Quando un puntatore viene acquisito da un elemento, solo l'oggetto riceve gli eventi di input del puntatore, anche quando il puntatore si sposta all'esterno dell'area di delimitazione dell'oggetto. Il IsInContact (pulsante del mouse premuto, tocco o stilo nel contatto) deve essere vero affinché CapturePointer abbia successo.

Evento Descrizione

PuntatoreAnnullato

Si verifica quando un puntatore viene cancellato dalla piattaforma. Ciò può verificarsi nelle circostanze seguenti:

  • I puntatori touch vengono annullati quando una penna viene rilevata entro la portata della superficie di input.
  • Un contatto attivo non viene rilevato per più di 100 ms.
  • Il monitor/display è stato modificato (risoluzione, impostazioni, configurazione multi-monitor).
  • Il desktop è bloccato o l'utente è disconnesso.
  • Il numero di contatti simultanei ha superato il numero supportato dal dispositivo.

PointerCaptureLost

Si verifica quando un altro elemento dell'interfaccia utente acquisisce il puntatore, il puntatore è stato rilasciato o un altro puntatore è stato acquisito a livello di codice.

Nota Non esiste alcun evento di acquisizione puntatore corrispondente.
 

puntatore immesso

Si verifica quando un cursore entra nell'area di delimitazione di un elemento. Ciò può verificarsi in modi leggermente diversi per l'input tramite tocco, touchpad, mouse e penna.

  • Il tocco richiede un contatto con il dito per attivare questo evento, sia da un tocco diretto sull'elemento sia dallo spostamento all'interno dell'area di delimitazione dell'elemento.
  • Mouse e touchpad hanno entrambi un cursore sullo schermo che è sempre visibile e attiva questo evento anche se non viene premuto alcun pulsante mouse o touchpad.
  • Come il tocco, la penna genera questo evento quando viene appoggiata direttamente sull'elemento o entrando nell'area di delimitazione dell'elemento. Tuttavia, la penna ha anche uno stato di hover (IsInRange) che, quando è true, attiva questo evento.

PuntatoreUscito

Si verifica quando un puntatore lascia l'area di delimitazione di un elemento. Ciò può verificarsi in modi leggermente diversi per l'input tramite tocco, touchpad, mouse e penna.

  • Il tocco richiede un contatto con il dito e attiva questo evento quando il puntatore si sposta fuori dall'area di delimitazione dell'elemento.
  • Mouse e touchpad hanno entrambi un cursore sullo schermo che è sempre visibile e attiva questo evento anche se non viene premuto alcun pulsante mouse o touchpad.
  • Come il tocco, la penna attiva questo evento quando si esce dall'area di delimitazione dell'elemento. Tuttavia, la penna ha anche uno stato di passaggio (IsInRange) che genera questo evento quando lo stato cambia da true a false.

Puntatore spostato

Si verifica quando un puntatore modifica le coordinate, lo stato del pulsante, la pressione, l'inclinazione o la geometria del contatto (ad esempio, larghezza e altezza) all'interno dell'area di delimitazione di un elemento. Ciò può verificarsi in modi leggermente diversi per l'input tramite tocco, touchpad, mouse e penna.

  • Il tocco richiede un contatto con un dito e genera questo evento solo quando si trova in contatto all'interno dell'area di delimitazione dell'elemento.
  • Mouse e touchpad hanno entrambi un cursore sullo schermo che è sempre visibile e attiva questo evento anche se non viene premuto alcun pulsante mouse o touchpad.
  • Come il tocco di uno schermo, la penna attiva questo evento quando entra in contatto all'interno dell'area di delimitazione dell'elemento. Tuttavia, la penna ha anche uno stato di sospensione (IsInRange) che, quando è vero e si trova all'interno dell'area di delimitazione dell'elemento, attiva questo evento.

PressioneDelPuntatore

Si verifica quando il puntatore indica un'azione di pressione (ad esempio un tocco, una pressione del pulsante del mouse, una pressione della penna o una pressione del pulsante del touchpad) all'interno dell'area di delimitazione di un elemento.

CapturePointer deve essere chiamato dal gestore per questo evento.

Rilascio del Puntatore

Si verifica quando il puntatore indica un'azione di rilascio (ad esempio un rilascio del tocco, un sollevamento del pulsante del mouse, una penna sollevata, o un rilascio del pulsante del touchpad) all'interno dell'area di delimitazione di un elemento o, se il puntatore viene catturato, all'esterno dell'area di delimitazione.

ModificaRotellaPuntatore

Si verifica quando la rotellina del mouse viene ruotata.

L'input del mouse è associato a un singolo puntatore assegnato quando viene rilevato per la prima volta l'input del mouse. Facendo clic su un pulsante del mouse (sinistra, rotellina o destra) viene creata un'associazione secondaria tra il puntatore e quel pulsante tramite l'evento PointerMoved.

 

Esempio di evento puntatore

Ecco alcuni frammenti di codice di un'app di rilevamento puntatore di base che illustrano come ascoltare e gestire gli eventi per più puntatori e ottenere varie proprietà per i puntatori associati.

l'interfaccia utente dell'applicazione Pointer

Scarica questo esempio da Esempio di input del puntatore (di base)

Creare l'interfaccia utente

Per questo esempio, utilizziamo un Rectangle (Target) come oggetto che riceve l'input del puntatore. Il colore della destinazione cambia quando lo stato del puntatore cambia.

I dettagli di ogni puntatore vengono visualizzati in un blocco di testo fluttuante che segue il puntatore mentre si muove. Gli eventi del puntatore stessi vengono segnalati nella RichTextBlock a destra del rettangolo.

Questo è il linguaggio XAML (Extensible Application Markup Language) per l'interfaccia utente in questo esempio.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="250"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="320" />
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Canvas Name="Container" 
            Grid.Column="0"
            Grid.Row="1"
            HorizontalAlignment="Center" 
            VerticalAlignment="Center" 
            Margin="245,0" 
            Height="320"  Width="640">
        <Rectangle Name="Target" 
                    Fill="#FF0000" 
                    Stroke="Black" 
                    StrokeThickness="0"
                    Height="320" Width="640" />
    </Canvas>
    <Grid Grid.Column="1" Grid.Row="0" Grid.RowSpan="3">
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Button Name="buttonClear" 
                Grid.Row="0"
                Content="Clear"
                Foreground="White"
                HorizontalAlignment="Stretch" 
                VerticalAlignment="Stretch">
        </Button>
        <ScrollViewer Name="eventLogScrollViewer" Grid.Row="1" 
                        VerticalScrollMode="Auto" 
                        Background="Black">                
            <RichTextBlock Name="eventLog"  
                        TextWrapping="Wrap" 
                        Foreground="#FFFFFF" 
                        ScrollViewer.VerticalScrollBarVisibility="Visible" 
                        ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                        Grid.ColumnSpan="2">
            </RichTextBlock>
        </ScrollViewer>
    </Grid>
</Grid>

Ascoltare gli eventi del puntatore

Nella maggior parte dei casi, è consigliabile ottenere informazioni sul puntatore tramite il PointerRoutedEventArgs del gestore eventi.

Se l'argomento evento non espone i dettagli del puntatore necessari, è possibile ottenere l'accesso alle informazioni estese PointerPoint esposte tramite il GetCurrentPoint e i metodi GetIntermediatePoints di PointerRoutedEventArgs.

Il codice seguente configura l'oggetto dizionario globale per tenere traccia di ogni puntatore attivo e identifica i vari listener di eventi del puntatore per l'oggetto di destinazione.

// Dictionary to maintain information about each active pointer. 
// An entry is added during PointerPressed/PointerEntered events and removed 
// during PointerReleased/PointerCaptureLost/PointerCanceled/PointerExited events.
Dictionary<uint, Windows.UI.Xaml.Input.Pointer> pointers;

public MainPage()
{
    this.InitializeComponent();

    // Initialize the dictionary.
    pointers = new Dictionary<uint, Windows.UI.Xaml.Input.Pointer>();

    // Declare the pointer event handlers.
    Target.PointerPressed += 
        new PointerEventHandler(Target_PointerPressed);
    Target.PointerEntered += 
        new PointerEventHandler(Target_PointerEntered);
    Target.PointerReleased += 
        new PointerEventHandler(Target_PointerReleased);
    Target.PointerExited += 
        new PointerEventHandler(Target_PointerExited);
    Target.PointerCanceled += 
        new PointerEventHandler(Target_PointerCanceled);
    Target.PointerCaptureLost += 
        new PointerEventHandler(Target_PointerCaptureLost);
    Target.PointerMoved += 
        new PointerEventHandler(Target_PointerMoved);
    Target.PointerWheelChanged += 
        new PointerEventHandler(Target_PointerWheelChanged);

    buttonClear.Click += 
        new RoutedEventHandler(ButtonClear_Click);
}

Gestire gli eventi del puntatore

Successivamente, utilizziamo il feedback dell'interfaccia utente per illustrare i gestori di eventi del puntatore di base.

  • Questo gestore gestisce l'evento PointerPressed. Aggiungiamo l'evento al registro eventi, aggiungiamo il puntatore al dizionario dei puntatori attivi e visualizziamo i dettagli del puntatore.

    Annotazioni

    gli eventi PointerPressed e PointerReleased non si verificano sempre in coppie. L'app deve restare in ascolto e gestire qualsiasi evento che possa concludere un puntatore verso il basso ( ad esempio PointerExited, PointerCancelede PointerCaptureLost).  

/// <summary>
/// The pointer pressed event handler.
/// PointerPressed and PointerReleased don't always occur in pairs. 
/// Your app should listen for and handle any event that can conclude 
/// a pointer down (PointerExited, PointerCanceled, PointerCaptureLost).
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
void Target_PointerPressed(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Update event log.
    UpdateEventLog("Down: " + ptrPt.PointerId);

    // Lock the pointer to the target.
    Target.CapturePointer(e.Pointer);

    // Update event log.
    UpdateEventLog("Pointer captured: " + ptrPt.PointerId);

    // Check if pointer exists in dictionary (ie, enter occurred prior to press).
    if (!pointers.ContainsKey(ptrPt.PointerId))
    {
        // Add contact to dictionary.
        pointers[ptrPt.PointerId] = e.Pointer;
    }

    // Change background color of target when pointer contact detected.
    Target.Fill = new SolidColorBrush(Windows.UI.Colors.Green);

    // Display pointer details.
    CreateInfoPop(ptrPt);
}
  • Questo gestore gestisce l'evento PointerEntered . Aggiungiamo l'evento al registro eventi, aggiungiamo il puntatore alla raccolta di puntatori e visualizziamo i dettagli del puntatore.
/// <summary>
/// The pointer entered event handler.
/// We do not capture the pointer on this event.
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
private void Target_PointerEntered(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Update event log.
    UpdateEventLog("Entered: " + ptrPt.PointerId);

    // Check if pointer already exists (if enter occurred prior to down).
    if (!pointers.ContainsKey(ptrPt.PointerId))
    {
        // Add contact to dictionary.
        pointers[ptrPt.PointerId] = e.Pointer;
    }

    if (pointers.Count == 0)
    {
        // Change background color of target when pointer contact detected.
        Target.Fill = new SolidColorBrush(Windows.UI.Colors.Blue);
    }

    // Display pointer details.
    CreateInfoPop(ptrPt);
}
  • Questo gestore di eventi gestisce l'evento PointerMoved . Aggiungiamo l'evento al Registro eventi e aggiorniamo i dettagli del puntatore.

    Importante

    L'input del mouse è associato a un singolo puntatore assegnato quando viene rilevato per la prima volta l'input del mouse. Facendo clic su un pulsante del mouse (sinistra, rotella o destra) viene creata un'associazione secondaria tra il puntatore e il pulsante tramite l'evento PointerPressed. L'evento PointerReleased viene generato solo quando lo stesso pulsante del mouse viene rilasciato (nessun altro pulsante può essere associato al puntatore fino al completamento dell'evento). A causa di questa associazione esclusiva, altri clic del pulsante del mouse vengono instradati tramite l'evento PointerMoved.  

/// <summary>
/// The pointer moved event handler.
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
private void Target_PointerMoved(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Multiple, simultaneous mouse button inputs are processed here.
    // Mouse input is associated with a single pointer assigned when 
    // mouse input is first detected. 
    // Clicking additional mouse buttons (left, wheel, or right) during 
    // the interaction creates secondary associations between those buttons 
    // and the pointer through the pointer pressed event. 
    // The pointer released event is fired only when the last mouse button 
    // associated with the interaction (not necessarily the initial button) 
    // is released. 
    // Because of this exclusive association, other mouse button clicks are 
    // routed through the pointer move event.          
    if (ptrPt.PointerDevice.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
    {
        if (ptrPt.Properties.IsLeftButtonPressed)
        {
            UpdateEventLog("Left button: " + ptrPt.PointerId);
        }
        if (ptrPt.Properties.IsMiddleButtonPressed)
        {
            UpdateEventLog("Wheel button: " + ptrPt.PointerId);
        }
        if (ptrPt.Properties.IsRightButtonPressed)
        {
            UpdateEventLog("Right button: " + ptrPt.PointerId);
        }
    }

    // Display pointer details.
    UpdateInfoPop(ptrPt);
}
  • Questo gestore gestisce l'evento PointerWheelChanged. Aggiungere l'evento al registro eventi, aggiungere il puntatore alla matrice di puntatori (se necessario) e visualizzare i dettagli del puntatore.
/// <summary>
/// The pointer wheel event handler.
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
private void Target_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Update event log.
    UpdateEventLog("Mouse wheel: " + ptrPt.PointerId);

    // Check if pointer already exists (for example, enter occurred prior to wheel).
    if (!pointers.ContainsKey(ptrPt.PointerId))
    {
        // Add contact to dictionary.
        pointers[ptrPt.PointerId] = e.Pointer;
    }

    // Display pointer details.
    CreateInfoPop(ptrPt);
}
  • Questo gestore gestisce l'evento PointerReleased in cui viene terminato il contatto con il digitalizzatore. Noi aggiungiamo l'evento al registro eventi, rimuoviamo il puntatore dalla raccolta di puntatori e aggiorniamo i dettagli del puntatore.
/// <summary>
/// The pointer released event handler.
/// PointerPressed and PointerReleased don't always occur in pairs. 
/// Your app should listen for and handle any event that can conclude 
/// a pointer down (PointerExited, PointerCanceled, PointerCaptureLost).
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
void Target_PointerReleased(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Update event log.
    UpdateEventLog("Up: " + ptrPt.PointerId);

    // If event source is mouse or touchpad and the pointer is still 
    // over the target, retain pointer and pointer details.
    // Return without removing pointer from pointers dictionary.
    // For this example, we assume a maximum of one mouse pointer.
    if (ptrPt.PointerDevice.PointerDeviceType != Windows.Devices.Input.PointerDeviceType.Mouse)
    {
        // Update target UI.
        Target.Fill = new SolidColorBrush(Windows.UI.Colors.Red);

        DestroyInfoPop(ptrPt);

        // Remove contact from dictionary.
        if (pointers.ContainsKey(ptrPt.PointerId))
        {
            pointers[ptrPt.PointerId] = null;
            pointers.Remove(ptrPt.PointerId);
        }

        // Release the pointer from the target.
        Target.ReleasePointerCapture(e.Pointer);

        // Update event log.
        UpdateEventLog("Pointer released: " + ptrPt.PointerId);
    }
    else
    {
        Target.Fill = new SolidColorBrush(Windows.UI.Colors.Blue);
    }
}
  • Questo gestore gestisce l'evento PointerExited (quando viene mantenuto il contatto con il digitalizzatore). Aggiungiamo l'evento al registro eventi, rimuoviamo il puntatore dall'array di puntatori e aggiorniamo i dettagli del puntatore.
/// <summary>
/// The pointer exited event handler.
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
private void Target_PointerExited(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Update event log.
    UpdateEventLog("Pointer exited: " + ptrPt.PointerId);

    // Remove contact from dictionary.
    if (pointers.ContainsKey(ptrPt.PointerId))
    {
        pointers[ptrPt.PointerId] = null;
        pointers.Remove(ptrPt.PointerId);
    }

    if (pointers.Count == 0)
    {
        Target.Fill = new SolidColorBrush(Windows.UI.Colors.Red);
    }

    // Update the UI and pointer details.
    DestroyInfoPop(ptrPt);
}
  • Questo gestore gestisce l'evento PointerCanceled. Aggiungiamo l'evento al registro eventi, rimuoviamo il puntatore dall'array di puntatori e aggiorniamo i dettagli del puntatore.
/// <summary>
/// The pointer canceled event handler.
/// Fires for various reasons, including: 
///    - Touch contact canceled by pen coming into range of the surface.
///    - The device doesn't report an active contact for more than 100ms.
///    - The desktop is locked or the user logged off. 
///    - The number of simultaneous contacts exceeded the number supported by the device.
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
private void Target_PointerCanceled(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Update event log.
    UpdateEventLog("Pointer canceled: " + ptrPt.PointerId);

    // Remove contact from dictionary.
    if (pointers.ContainsKey(ptrPt.PointerId))
    {
        pointers[ptrPt.PointerId] = null;
        pointers.Remove(ptrPt.PointerId);
    }

    if (pointers.Count == 0)
    {
        Target.Fill = new SolidColorBrush(Windows.UI.Colors.Black);
    }

    DestroyInfoPop(ptrPt);
}
  • Questo gestore gestisce l'evento PointerCaptureLost. Aggiungiamo l'evento al registro eventi, rimuoviamo il puntatore dall'array di puntatori e aggiorniamo i dettagli del puntatore.

    Annotazioni

    PointerCaptureLost può verificarsi invece di PointerReleased. L'acquisizione del puntatore può essere persa per vari motivi, tra cui l'interazione dell'utente, la cattura programmata di un altro puntatore, chiamando PointerReleased.  

/// <summary>
/// The pointer capture lost event handler.
/// Fires for various reasons, including: 
///    - User interactions
///    - Programmatic capture of another pointer
///    - Captured pointer was deliberately released
// PointerCaptureLost can fire instead of PointerReleased. 
/// </summary>
/// <param name="sender">Source of the pointer event.</param>
/// <param name="e">Event args for the pointer routed event.</param>
private void Target_PointerCaptureLost(object sender, PointerRoutedEventArgs e)
{
    // Prevent most handlers along the event route from handling the same event again.
    e.Handled = true;

    PointerPoint ptrPt = e.GetCurrentPoint(Target);

    // Update event log.
    UpdateEventLog("Pointer capture lost: " + ptrPt.PointerId);

    if (pointers.Count == 0)
    {
        Target.Fill = new SolidColorBrush(Windows.UI.Colors.Black);
    }

    // Remove contact from dictionary.
    if (pointers.ContainsKey(ptrPt.PointerId))
    {
        pointers[ptrPt.PointerId] = null;
        pointers.Remove(ptrPt.PointerId);
    }

    DestroyInfoPop(ptrPt);
}

Ottenere le proprietà del puntatore

Come indicato in precedenza, è necessario ottenere informazioni più dettagliate sul puntatore da un oggetto Windows.UI.Input.PointerPoint ottenuto tramite i metodi GetCurrentPoint e GetIntermediatePoints di PointerRoutedEventArgs. I frammenti di codice seguenti mostrano come.

  • Prima di tutto, creiamo un nuovo TextBlock per ogni puntatore.
/// <summary>
/// Create the pointer info popup.
/// </summary>
/// <param name="ptrPt">Reference to the input pointer.</param>
void CreateInfoPop(PointerPoint ptrPt)
{
    TextBlock pointerDetails = new TextBlock();
    pointerDetails.Name = ptrPt.PointerId.ToString();
    pointerDetails.Foreground = new SolidColorBrush(Windows.UI.Colors.White);
    pointerDetails.Text = QueryPointer(ptrPt);

    TranslateTransform x = new TranslateTransform();
    x.X = ptrPt.Position.X + 20;
    x.Y = ptrPt.Position.Y + 20;
    pointerDetails.RenderTransform = x;

    Container.Children.Add(pointerDetails);
}
  • Viene quindi fornito un modo per aggiornare le informazioni del puntatore in un TextBlock esistente associato a tale puntatore.
/// <summary>
/// Update the pointer info popup.
/// </summary>
/// <param name="ptrPt">Reference to the input pointer.</param>
void UpdateInfoPop(PointerPoint ptrPt)
{
    foreach (var pointerDetails in Container.Children)
    {
        if (pointerDetails.GetType().ToString() == "Windows.UI.Xaml.Controls.TextBlock")
        {
            TextBlock textBlock = (TextBlock)pointerDetails;
            if (textBlock.Name == ptrPt.PointerId.ToString())
            {
                // To get pointer location details, we need extended pointer info.
                // We get the pointer info through the getCurrentPoint method
                // of the event argument. 
                TranslateTransform x = new TranslateTransform();
                x.X = ptrPt.Position.X + 20;
                x.Y = ptrPt.Position.Y + 20;
                pointerDetails.RenderTransform = x;
                textBlock.Text = QueryPointer(ptrPt);
            }
        }
    }
}
  • Infine, interroghiamo varie proprietà del puntatore.
/// <summary>
/// Get pointer details.
/// </summary>
/// <param name="ptrPt">Reference to the input pointer.</param>
/// <returns>A string composed of pointer details.</returns>
String QueryPointer(PointerPoint ptrPt)
{
    String details = "";

    switch (ptrPt.PointerDevice.PointerDeviceType)
    {
        case Windows.Devices.Input.PointerDeviceType.Mouse:
            details += "\nPointer type: mouse";
            break;
        case Windows.Devices.Input.PointerDeviceType.Pen:
            details += "\nPointer type: pen";
            if (ptrPt.IsInContact)
            {
                details += "\nPressure: " + ptrPt.Properties.Pressure;
                details += "\nrotation: " + ptrPt.Properties.Orientation;
                details += "\nTilt X: " + ptrPt.Properties.XTilt;
                details += "\nTilt Y: " + ptrPt.Properties.YTilt;
                details += "\nBarrel button pressed: " + ptrPt.Properties.IsBarrelButtonPressed;
            }
            break;
        case Windows.Devices.Input.PointerDeviceType.Touch:
            details += "\nPointer type: touch";
            details += "\nrotation: " + ptrPt.Properties.Orientation;
            details += "\nTilt X: " + ptrPt.Properties.XTilt;
            details += "\nTilt Y: " + ptrPt.Properties.YTilt;
            break;
        default:
            details += "\nPointer type: n/a";
            break;
    }

    GeneralTransform gt = Target.TransformToVisual(this);
    Point screenPoint;

    screenPoint = gt.TransformPoint(new Point(ptrPt.Position.X, ptrPt.Position.Y));
    details += "\nPointer Id: " + ptrPt.PointerId.ToString() +
        "\nPointer location (target): " + Math.Round(ptrPt.Position.X) + ", " + Math.Round(ptrPt.Position.Y) +
        "\nPointer location (container): " + Math.Round(screenPoint.X) + ", " + Math.Round(screenPoint.Y);

    return details;
}

Puntatore primario

Alcuni dispositivi di input, come un digitalizzatore touch o un touchpad, supportano più di un unico puntatore tipico di un mouse o una penna (nella maggior parte dei casi, poiché il Surface Hub supporta due penne).

Utilizzare la proprietà IsPrimary di sola lettura della classe PointerPointerProperties per identificare e distinguere un singolo puntatore primario (il puntatore primario è sempre il primo puntatore rilevato durante una sequenza di input).

Identificando il puntatore primario, è possibile usarlo per emulare l'input del mouse o della penna, personalizzare le interazioni o fornire altre funzionalità o interfaccia utente specifiche.

Annotazioni

Se il puntatore primario viene rilasciato, annullato o perso durante una sequenza di input, un puntatore di input primario non viene creato finché non viene avviata una nuova sequenza di input (una sequenza di input termina quando tutti i puntatori sono stati rilasciati, annullati o persi).

Esempio di animazione del puntatore primario

Questi frammenti di codice mostrano come fornire un feedback visivo speciale per consentire a un utente di distinguere gli input del puntatore nell'applicazione.

Questa particolare app usa sia il colore che l'animazione per evidenziare il puntatore primario.

'applicazione Pointer con feedback visivo animato

Scaricare questo esempio da esempio di input del puntatore (UserControl con animazione)

Feedback visivo

Definiamo un UserControl, basato su un oggetto XAML Ellipse, che evidenzia dove si trova ogni puntatore sulla tela e utilizza un Storyboard per animare l'ellisse corrispondente al puntatore primario.

ecco il codice XAML:

<UserControl
    x:Class="UWP_Pointers.PointerEllipse"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UWP_Pointers"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="100"
    d:DesignWidth="100">

    <UserControl.Resources>
        <Style x:Key="EllipseStyle" TargetType="Ellipse">
            <Setter Property="Transitions">
                <Setter.Value>
                    <TransitionCollection>
                        <ContentThemeTransition/>
                    </TransitionCollection>
                </Setter.Value>
            </Setter>
        </Style>
        
        <Storyboard x:Name="myStoryboard">
            <!-- Animates the value of a Double property between 
            two target values using linear interpolation over the 
            specified Duration. -->
            <DoubleAnimation
              Storyboard.TargetName="ellipse"
              Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleY)"  
              Duration="0:0:1" 
              AutoReverse="True" 
              RepeatBehavior="Forever" From="1.0" To="1.4">
            </DoubleAnimation>

            <!-- Animates the value of a Double property between 
            two target values using linear interpolation over the 
            specified Duration. -->
            <DoubleAnimation
              Storyboard.TargetName="ellipse"
              Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleX)"  
              Duration="0:0:1" 
              AutoReverse="True" 
              RepeatBehavior="Forever" From="1.0" To="1.4">
            </DoubleAnimation>

            <!-- Animates the value of a Color property between 
            two target values using linear interpolation over the 
            specified Duration. -->
            <ColorAnimation 
                Storyboard.TargetName="ellipse" 
                EnableDependentAnimation="True" 
                Storyboard.TargetProperty="(Fill).(SolidColorBrush.Color)" 
                From="White" To="Red"  Duration="0:0:1" 
                AutoReverse="True" RepeatBehavior="Forever"/>
        </Storyboard>
    </UserControl.Resources>

    <Grid x:Name="CompositionContainer">
        <Ellipse Name="ellipse" 
        StrokeThickness="2" 
        Width="{x:Bind Diameter}" 
        Height="{x:Bind Diameter}"  
        Style="{StaticResource EllipseStyle}" />
    </Grid>
</UserControl>

Ecco il "code-behind":

using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

// The User Control item template is documented at 
// https://go.microsoft.com/fwlink/?LinkId=234236

namespace UWP_Pointers
{
    /// <summary>
    /// Pointer feedback object.
    /// </summary>
    public sealed partial class PointerEllipse : UserControl
    {
        // Reference to the application canvas.
        Canvas canvas;

        /// <summary>
        /// Ellipse UI for pointer feedback.
        /// </summary>
        /// <param name="c">The drawing canvas.</param>
        public PointerEllipse(Canvas c)
        {
            this.InitializeComponent();
            canvas = c;
        }

        /// <summary>
        /// Gets or sets the pointer Id to associate with the PointerEllipse object.
        /// </summary>
        public uint PointerId
        {
            get { return (uint)GetValue(PointerIdProperty); }
            set { SetValue(PointerIdProperty, value); }
        }
        // Using a DependencyProperty as the backing store for PointerId.  
        // This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PointerIdProperty =
            DependencyProperty.Register("PointerId", typeof(uint), 
                typeof(PointerEllipse), new PropertyMetadata(null));


        /// <summary>
        /// Gets or sets whether the associated pointer is Primary.
        /// </summary>
        public bool PrimaryPointer
        {
            get { return (bool)GetValue(PrimaryPointerProperty); }
            set
            {
                SetValue(PrimaryPointerProperty, value);
            }
        }
        // Using a DependencyProperty as the backing store for PrimaryPointer.  
        // This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PrimaryPointerProperty =
            DependencyProperty.Register("PrimaryPointer", typeof(bool), 
                typeof(PointerEllipse), new PropertyMetadata(false));


        /// <summary>
        /// Gets or sets the ellipse style based on whether the pointer is Primary.
        /// </summary>
        public bool PrimaryEllipse 
        {
            get { return (bool)GetValue(PrimaryEllipseProperty); }
            set
            {
                SetValue(PrimaryEllipseProperty, value);
                if (value)
                {
                    SolidColorBrush fillBrush = 
                        (SolidColorBrush)Application.Current.Resources["PrimaryFillBrush"];
                    SolidColorBrush strokeBrush = 
                        (SolidColorBrush)Application.Current.Resources["PrimaryStrokeBrush"];

                    ellipse.Fill = fillBrush;
                    ellipse.Stroke = strokeBrush;
                    ellipse.RenderTransform = new CompositeTransform();
                    ellipse.RenderTransformOrigin = new Point(.5, .5);
                    myStoryboard.Begin();
                }
                else
                {
                    SolidColorBrush fillBrush = 
                        (SolidColorBrush)Application.Current.Resources["SecondaryFillBrush"];
                    SolidColorBrush strokeBrush = 
                        (SolidColorBrush)Application.Current.Resources["SecondaryStrokeBrush"];
                    ellipse.Fill = fillBrush;
                    ellipse.Stroke = strokeBrush;
                }
            }
        }
        // Using a DependencyProperty as the backing store for PrimaryEllipse.  
        // This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PrimaryEllipseProperty =
            DependencyProperty.Register("PrimaryEllipse", 
                typeof(bool), typeof(PointerEllipse), new PropertyMetadata(false));


        /// <summary>
        /// Gets or sets the diameter of the PointerEllipse object.
        /// </summary>
        public int Diameter
        {
            get { return (int)GetValue(DiameterProperty); }
            set { SetValue(DiameterProperty, value); }
        }
        // Using a DependencyProperty as the backing store for Diameter.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DiameterProperty =
            DependencyProperty.Register("Diameter", typeof(int), 
                typeof(PointerEllipse), new PropertyMetadata(120));
    }
}

Creare l'interfaccia utente

L'interfaccia utente in questo esempio è limitata all'input Canvas in cui si tiene traccia di qualsiasi puntatore ed esegue il rendering degli indicatori di puntatore e dell'animazione del puntatore primario (se applicabile), insieme a una barra di intestazione contenente un contatore del puntatore e un identificatore di puntatore primario.

Ecco il MainPage.xaml:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel x:Name="HeaderPanel" 
                Orientation="Horizontal" 
                Grid.Row="0">
        <StackPanel.Transitions>
            <TransitionCollection>
                <AddDeleteThemeTransition/>
            </TransitionCollection>
        </StackPanel.Transitions>
        <TextBlock x:Name="Header" 
                    Text="Basic pointer tracking sample - IsPrimary" 
                    Style="{ThemeResource HeaderTextBlockStyle}" 
                    Margin="10,0,0,0" />
        <TextBlock x:Name="PointerCounterLabel"
                    VerticalAlignment="Center"                 
                    Style="{ThemeResource BodyTextBlockStyle}"
                    Text="Number of pointers: " 
                    Margin="50,0,0,0"/>
        <TextBlock x:Name="PointerCounter"
                    VerticalAlignment="Center"                 
                    Style="{ThemeResource BodyTextBlockStyle}"
                    Text="0" 
                    Margin="10,0,0,0"/>
        <TextBlock x:Name="PointerPrimaryLabel"
                    VerticalAlignment="Center"                 
                    Style="{ThemeResource BodyTextBlockStyle}"
                    Text="Primary: " 
                    Margin="50,0,0,0"/>
        <TextBlock x:Name="PointerPrimary"
                    VerticalAlignment="Center"                 
                    Style="{ThemeResource BodyTextBlockStyle}"
                    Text="n/a" 
                    Margin="10,0,0,0"/>
    </StackPanel>
    
    <Grid Grid.Row="1">
        <!--The canvas where we render the pointer UI.-->
        <Canvas x:Name="pointerCanvas"/>
    </Grid>
</Grid>

Gestire gli eventi del puntatore

Infine, definiamo i nostri gestori degli eventi di base del puntatore nel code-behind di MainPage.xaml.cs. Non riprodurremo il codice qui, poiché le basi sono state coperte nell'esempio precedente, ma puoi scaricare il campione funzionante da esempio di input del puntatore (UserControl con animazione).

Esempi di argomenti

Altri campioni

Esempi di archivio