Condividi tramite


Creazione di un controllo di input penna

È possibile creare un controllo personalizzato per eseguire il rendering dinamico e statico dell'input penna, ovvero per eseguire il rendering dell'input penna mentre un utente traccia un tratto, in modo che l'input sembri "fluire" dalla penna del Tablet PC, e quindi visualizzarlo dopo che è stato aggiunto al controllo, tramite la penna del Tablet PC oppure incollandolo dagli Appunti o caricandolo da un file. Per eseguire il rendering dinamico dell'input penna, è necessario che il controllo utilizzi un oggetto DynamicRenderer. Per eseguire il rendering statico dell'input penna, è necessario eseguire l'override dei metodi degli eventi dello stilo (OnStylusDown, OnStylusMove e OnStylusUp) per raccogliere i dati StylusPoint, creare tratti e aggiungerli a un oggetto InkPresenter, che esegue il rendering dell'input penna sul controllo.

In questo argomento sono contenute le seguenti sottosezioni:

  • Procedura: raccogliere dati dei punti dello stilo e creare tratti input penna

  • Procedura: abilitare il controllo per l'accettazione di input dal mouse

  • Esempio completo

  • Utilizzo di plug-in aggiuntivi e oggetti DynamicRenderer

  • Conclusione

Procedura: raccogliere dati dei punti dello stilo e creare tratti input penna

Per creare un controllo che raccolga e gestisca tratti input penna, effettuare le operazioni seguenti:

  1. Derivare una classe da Control o da una delle classi derivate da Control, ad esempio Label.

    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports System.Windows.Ink
    Imports System.Windows.Input
    Imports System.Windows.Input.StylusPlugIns
    Imports System.Windows.Controls
    Imports System.Windows
    
    
    ...
    
    
    Class InkControl
        Inherits Label
    
    
    ...
    
    
    End Class 'StylusControl
    
    using System;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Input.StylusPlugIns;
    using System.Windows.Controls;
    using System.Windows;
    
    
    ...
    
    
    class InkControl : Label
    {
    
    
    ...
    
    
    }
    
  2. Aggiungere un oggetto InkPresenter alla classe e impostare la proprietà Content sul nuovo oggetto InkPresenter.

    Private ip As InkPresenter
    
    Public Sub New()
        ' Add an InkPresenter for drawing.
        ip = New InkPresenter()
        Me.Content = ip
    
    End Sub
    
    InkPresenter ip;
    
    public InkControl()
    {
        // Add an InkPresenter for drawing.
        ip = new InkPresenter();
        this.Content = ip;
    }
    
  3. Collegare la proprietà RootVisual dell'oggetto DynamicRenderer all'oggetto InkPresenter effettuando una chiamata al metodo AttachVisuals e aggiungere l'oggetto DynamicRenderer all'insieme StylusPlugIns. In questo modo l'oggetto InkPresenter visualizza l'input penna via via che i punti dei dati dello stilo vengono raccolti dal controllo.

    Public Sub New()
    
    
    ...
    
    
        ' Add a dynamic renderer that 
        ' draws ink as it "flows" from the stylus.
        dr = New DynamicRenderer()
        ip.AttachVisuals(dr.RootVisual, dr.DrawingAttributes)
        Me.StylusPlugIns.Add(dr)
    
    End Sub
    
    public InkControl()
    {
    
    
    ...
    
    
        // Add a dynamic renderer that 
        // draws ink as it "flows" from the stylus.
        dr = new DynamicRenderer();
        ip.AttachVisuals(dr.RootVisual, dr.DrawingAttributes);
        this.StylusPlugIns.Add(dr);
    
    }
    
  4. Eseguire l'override del metodo OnStylusDown. In questo metodo acquisire lo stilo con una chiamata a Capture. Acquisendo lo stilo, il controllo continuerà a ricevere gli eventi StylusMove e StylusUp, anche se lo stilo lascia i limiti del controllo. Questa operazione non è obbligatoria, ma è consigliabile nella maggior parte dei casi per migliorare l'esperienza dell'utente. Creare un nuovo oggetto StylusPointCollection per raccogliere i dati StylusPoint. Infine, aggiungere l'insieme iniziale dei dati StylusPoint all'oggetto StylusPointCollection.

    Protected Overrides Sub OnStylusDown(ByVal e As StylusDownEventArgs)
        ' Capture the stylus so all stylus input is routed to this control.
        Stylus.Capture(Me)
    
        ' Allocate memory for the StylusPointsCollection and
        ' add the StylusPoints that have come in so far.
        stylusPoints = New StylusPointCollection()
        Dim eventPoints As StylusPointCollection = e.GetStylusPoints(Me, stylusPoints.Description)
    
        stylusPoints.Add(eventPoints)
    
    End Sub 'OnStylusDown
    
    protected override void OnStylusDown(StylusDownEventArgs e)
    {
        // Capture the stylus so all stylus input is routed to this control.
        Stylus.Capture(this);
    
        // Allocate memory for the StylusPointsCollection and
        // add the StylusPoints that have come in so far.
        stylusPoints = new StylusPointCollection();
        StylusPointCollection eventPoints = 
            e.GetStylusPoints(this, stylusPoints.Description);
    
        stylusPoints.Add(eventPoints);
    
    }
    
  5. Eseguire l'override del metodo OnStylusMove e aggiungere i dati StylusPoint all'oggetto StylusPointCollection creato in precedenza.

    Protected Overrides Sub OnStylusMove(ByVal e As StylusEventArgs)
    
        If stylusPoints Is Nothing Then
            Return
        End If
    
        ' Add the StylusPoints that have come in since the 
        ' last call to OnStylusMove.
        Dim newStylusPoints As StylusPointCollection = e.GetStylusPoints(Me, stylusPoints.Description)
        stylusPoints.Add(newStylusPoints)
    
    End Sub 'OnStylusMove
    
    protected override void OnStylusMove(StylusEventArgs e)
    {
        if (stylusPoints == null)
        {
            return;
        }
    
        // Add the StylusPoints that have come in since the 
        // last call to OnStylusMove.
        StylusPointCollection newStylusPoints = 
            e.GetStylusPoints(this, stylusPoints.Description);
        stylusPoints.Add(newStylusPoints);
    }
    
  6. Eseguire l'override del metodo OnStylusUp e creare un nuovo oggetto Stroke con i dati StylusPointCollection. Aggiungere il nuovo oggetto Stroke creato all'insieme Strokes dell'oggetto InkPresenter e rilasciare l'acquisizione dello stilo.

    Protected Overrides Sub OnStylusUp(ByVal e As StylusEventArgs)
        ' Allocate memory for the StylusPointsCollection, if necessary.
        If stylusPoints Is Nothing Then
            Return
        End If
    
        ' Add the StylusPoints that have come in since the 
        ' last call to OnStylusMove.
        Dim newStylusPoints As StylusPointCollection = e.GetStylusPoints(Me, stylusPoints.Description)
        stylusPoints.Add(newStylusPoints)
    
        ' Create a new stroke from all the StylusPoints since OnStylusDown.
        Dim stroke As New Stroke(stylusPoints)
    
        ' Add the new stroke to the Strokes collection of the InkPresenter.
        ip.Strokes.Add(stroke)
    
        ' Clear the StylusPointsCollection.
        stylusPoints = Nothing
    
        ' Release stylus capture.
        Stylus.Capture(Nothing)
    
    End Sub 'OnStylusUp
    
    protected override void OnStylusUp(StylusEventArgs e)
    {
        if (stylusPoints == null)
        {
            return;
        }
    
        // Add the StylusPoints that have come in since the 
        // last call to OnStylusMove.
        StylusPointCollection newStylusPoints = 
            e.GetStylusPoints(this, stylusPoints.Description);
        stylusPoints.Add(newStylusPoints);
    
        // Create a new stroke from all the StylusPoints since OnStylusDown.
        Stroke stroke = new Stroke(stylusPoints);
    
        // Add the new stroke to the Strokes collection of the InkPresenter.
        ip.Strokes.Add(stroke);
    
        // Clear the StylusPointsCollection.
        stylusPoints = null;
    
        // Release stylus capture.
        Stylus.Capture(null);
    }
    

Procedura: abilitare il controllo per l'accettazione di input dal mouse

Se si aggiunge all'applicazione e si esegue il controllo precedente, quindi si utilizza il mouse come dispositivo di input, si noterà che i tratti non vengono mantenuti. Per mantenere i tratti quando si utilizza il mouse come dispositivo di input, effettuare le operazioni seguenti:

  1. Eseguire l'override del metodo OnMouseLeftButtonDown e creare un nuovo oggetto StylusPointCollection. Ottenere la posizione del mouse quando si è verificato l'evento e creare un oggetto StylusPoint utilizzando i dati dei punti, quindi aggiungere l'oggetto StylusPoint all'oggetto StylusPointCollection.

    Protected Overrides Sub OnMouseLeftButtonDown(ByVal e As MouseButtonEventArgs)
    
        MyBase.OnMouseLeftButtonDown(e)
    
        ' If a stylus generated this event, return.
        If Not (e.StylusDevice Is Nothing) Then
            Return
        End If
    
        ' Start collecting the points.
        stylusPoints = New StylusPointCollection()
        Dim pt As Point = e.GetPosition(Me)
        stylusPoints.Add(New StylusPoint(pt.X, pt.Y))
    
    End Sub 'OnMouseLeftButtonDown
    
    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
    
        base.OnMouseLeftButtonDown(e);
    
        // If a stylus generated this event, return.
        if (e.StylusDevice != null)
        {
            return;
        }
    
        // Start collecting the points.
        stylusPoints = new StylusPointCollection();
        Point pt = e.GetPosition(this);
        stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
    
    }
    
  2. Eseguire l'override del metodo OnMouseMove. Ottenere la posizione del mouse quando si è verificato l'evento e creare un oggetto StylusPoint utilizzando i dati dei punti. Aggiungere l'oggetto StylusPoint all'oggetto StylusPointCollection creato in precedenza.

    Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
    
        MyBase.OnMouseMove(e)
    
        ' If a stylus generated this event, return.
        If Not (e.StylusDevice Is Nothing) Then
            Return
        End If
    
        ' Don't collect points unless the left mouse button
        ' is down.
        If e.LeftButton = MouseButtonState.Released Then
            Return
        End If
    
        If stylusPoints Is Nothing Then
            Return
        End If
    
        Dim pt As Point = e.GetPosition(Me)
        stylusPoints.Add(New StylusPoint(pt.X, pt.Y))
    
    End Sub 'OnMouseMove
    
    protected override void OnMouseMove(MouseEventArgs e)
    {
    
        base.OnMouseMove(e);
    
        // If a stylus generated this event, return.
        if (e.StylusDevice != null)
        {
            return;
        }
    
        // Don't collect points unless the left mouse button
        // is down.
        if (e.LeftButton == MouseButtonState.Released || 
            stylusPoints == null)
        {
            return;
        }
    
        Point pt = e.GetPosition(this);
        stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
    }
    
  3. Eseguire l'override del metodo OnMouseLeftButtonUp. Creare un nuovo oggetto Stroke con i dati StylusPointCollection e aggiungere il nuovo oggetto Stroke creato all'insieme Strokes dell'oggetto InkPresenter.

    Protected Overrides Sub OnMouseLeftButtonUp(ByVal e As MouseButtonEventArgs)
    
        MyBase.OnMouseLeftButtonUp(e)
    
        ' If a stylus generated this event, return.
        If Not (e.StylusDevice Is Nothing) Then
            Return
        End If
    
        If stylusPoints Is Nothing Then
            stylusPoints = New StylusPointCollection()
        End If
    
        Dim pt As Point = e.GetPosition(Me)
        stylusPoints.Add(New StylusPoint(pt.X, pt.Y))
    
        ' Create a stroke and add it to the InkPresenter.
        Dim stroke As New Stroke(stylusPoints)
        stroke.DrawingAttributes = dr.DrawingAttributes
        ip.Strokes.Add(stroke)
    
        stylusPoints = Nothing
    
    End Sub 'OnMouseLeftButtonUp 
    
    protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
    {
    
        base.OnMouseLeftButtonUp(e);
    
        // If a stylus generated this event, return.
        if (e.StylusDevice != null)
        {
            return;
        }
    
        if (stylusPoints == null)
        {
            return;
        }
    
        Point pt = e.GetPosition(this);
        stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
    
        // Create a stroke and add it to the InkPresenter.
        Stroke stroke = new Stroke(stylusPoints);
        stroke.DrawingAttributes = dr.DrawingAttributes;
        ip.Strokes.Add(stroke);
    
        stylusPoints = null;
    
    }
    

Esempio completo

Nell'esempio seguente viene illustrato un controllo personalizzato che raccoglie l'input penna quando l'utente utilizza il mouse o la penna.

Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Windows.Ink
Imports System.Windows.Input
Imports System.Windows.Input.StylusPlugIns
Imports System.Windows.Controls
Imports System.Windows


...


' A control for managing ink input
Class InkControl
    Inherits Label
    Private ip As InkPresenter
    Private dr As DynamicRenderer

    ' The StylusPointsCollection that gathers points 
    ' before Stroke from is created.
    Private stylusPoints As StylusPointCollection = Nothing


    Public Sub New()
        ' Add an InkPresenter for drawing.
        ip = New InkPresenter()
        Me.Content = ip

        ' Add a dynamic renderer that 
        ' draws ink as it "flows" from the stylus.
        dr = New DynamicRenderer()
        ip.AttachVisuals(dr.RootVisual, dr.DrawingAttributes)
        Me.StylusPlugIns.Add(dr)

        Dim cdr As New CustomDynamicRenderer()
        ip.AttachVisuals(cdr.RootVisual, cdr.DrawingAttributes)
        Me.StylusPlugIns.Add(cdr)

    End Sub 'New

    Shared Sub New()

        ' Allow ink to be drawn only within the bounds of the control.
        Dim owner As Type = GetType(InkControl)
        ClipToBoundsProperty.OverrideMetadata(owner, New FrameworkPropertyMetadata(True))

    End Sub 'New

    Protected Overrides Sub OnStylusDown(ByVal e As StylusDownEventArgs)
        ' Capture the stylus so all stylus input is routed to this control.
        Stylus.Capture(Me)

        ' Allocate memory for the StylusPointsCollection and
        ' add the StylusPoints that have come in so far.
        stylusPoints = New StylusPointCollection()
        Dim eventPoints As StylusPointCollection = e.GetStylusPoints(Me, stylusPoints.Description)

        stylusPoints.Add(eventPoints)

    End Sub 'OnStylusDown

    Protected Overrides Sub OnStylusMove(ByVal e As StylusEventArgs)

        If stylusPoints Is Nothing Then
            Return
        End If

        ' Add the StylusPoints that have come in since the 
        ' last call to OnStylusMove.
        Dim newStylusPoints As StylusPointCollection = e.GetStylusPoints(Me, stylusPoints.Description)
        stylusPoints.Add(newStylusPoints)

    End Sub 'OnStylusMove

    Protected Overrides Sub OnStylusUp(ByVal e As StylusEventArgs)
        ' Allocate memory for the StylusPointsCollection, if necessary.
        If stylusPoints Is Nothing Then
            Return
        End If

        ' Add the StylusPoints that have come in since the 
        ' last call to OnStylusMove.
        Dim newStylusPoints As StylusPointCollection = e.GetStylusPoints(Me, stylusPoints.Description)
        stylusPoints.Add(newStylusPoints)

        ' Create a new stroke from all the StylusPoints since OnStylusDown.
        Dim stroke As New Stroke(stylusPoints)

        ' Add the new stroke to the Strokes collection of the InkPresenter.
        ip.Strokes.Add(stroke)

        ' Clear the StylusPointsCollection.
        stylusPoints = Nothing

        ' Release stylus capture.
        Stylus.Capture(Nothing)

    End Sub 'OnStylusUp

    Protected Overrides Sub OnMouseLeftButtonDown(ByVal e As MouseButtonEventArgs)

        MyBase.OnMouseLeftButtonDown(e)

        ' If a stylus generated this event, return.
        If Not (e.StylusDevice Is Nothing) Then
            Return
        End If

        ' Start collecting the points.
        stylusPoints = New StylusPointCollection()
        Dim pt As Point = e.GetPosition(Me)
        stylusPoints.Add(New StylusPoint(pt.X, pt.Y))

    End Sub 'OnMouseLeftButtonDown

    Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)

        MyBase.OnMouseMove(e)

        ' If a stylus generated this event, return.
        If Not (e.StylusDevice Is Nothing) Then
            Return
        End If

        ' Don't collect points unless the left mouse button
        ' is down.
        If e.LeftButton = MouseButtonState.Released Then
            Return
        End If

        If stylusPoints Is Nothing Then
            Return
        End If

        Dim pt As Point = e.GetPosition(Me)
        stylusPoints.Add(New StylusPoint(pt.X, pt.Y))

    End Sub 'OnMouseMove

    Protected Overrides Sub OnMouseLeftButtonUp(ByVal e As MouseButtonEventArgs)

        MyBase.OnMouseLeftButtonUp(e)

        ' If a stylus generated this event, return.
        If Not (e.StylusDevice Is Nothing) Then
            Return
        End If

        If stylusPoints Is Nothing Then
            stylusPoints = New StylusPointCollection()
        End If

        Dim pt As Point = e.GetPosition(Me)
        stylusPoints.Add(New StylusPoint(pt.X, pt.Y))

        ' Create a stroke and add it to the InkPresenter.
        Dim stroke As New Stroke(stylusPoints)
        stroke.DrawingAttributes = dr.DrawingAttributes
        ip.Strokes.Add(stroke)

        stylusPoints = Nothing

    End Sub 'OnMouseLeftButtonUp 
End Class 'StylusControl
using System;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Controls;
using System.Windows;


...


// A control for managing ink input
class InkControl : Label
{
    InkPresenter ip;
    DynamicRenderer dr;

    // The StylusPointsCollection that gathers points 
    // before Stroke from is created.
    StylusPointCollection stylusPoints = null;

    public InkControl()
    {
        // Add an InkPresenter for drawing.
        ip = new InkPresenter();
        this.Content = ip;

        // Add a dynamic renderer that 
        // draws ink as it "flows" from the stylus.
        dr = new DynamicRenderer();
        ip.AttachVisuals(dr.RootVisual, dr.DrawingAttributes);
        this.StylusPlugIns.Add(dr);

    }

    static InkControl()
    {
        // Allow ink to be drawn only within the bounds of the control.
        Type owner = typeof(InkControl);
        ClipToBoundsProperty.OverrideMetadata(owner,
            new FrameworkPropertyMetadata(true));
    }

    protected override void OnStylusDown(StylusDownEventArgs e)
    {
        // Capture the stylus so all stylus input is routed to this control.
        Stylus.Capture(this);

        // Allocate memory for the StylusPointsCollection and
        // add the StylusPoints that have come in so far.
        stylusPoints = new StylusPointCollection();
        StylusPointCollection eventPoints = 
            e.GetStylusPoints(this, stylusPoints.Description);

        stylusPoints.Add(eventPoints);

    }

    protected override void OnStylusMove(StylusEventArgs e)
    {
        if (stylusPoints == null)
        {
            return;
        }

        // Add the StylusPoints that have come in since the 
        // last call to OnStylusMove.
        StylusPointCollection newStylusPoints = 
            e.GetStylusPoints(this, stylusPoints.Description);
        stylusPoints.Add(newStylusPoints);
    }

    protected override void OnStylusUp(StylusEventArgs e)
    {
        if (stylusPoints == null)
        {
            return;
        }

        // Add the StylusPoints that have come in since the 
        // last call to OnStylusMove.
        StylusPointCollection newStylusPoints = 
            e.GetStylusPoints(this, stylusPoints.Description);
        stylusPoints.Add(newStylusPoints);

        // Create a new stroke from all the StylusPoints since OnStylusDown.
        Stroke stroke = new Stroke(stylusPoints);

        // Add the new stroke to the Strokes collection of the InkPresenter.
        ip.Strokes.Add(stroke);

        // Clear the StylusPointsCollection.
        stylusPoints = null;

        // Release stylus capture.
        Stylus.Capture(null);
    }

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {

        base.OnMouseLeftButtonDown(e);

        // If a stylus generated this event, return.
        if (e.StylusDevice != null)
        {
            return;
        }

        // Start collecting the points.
        stylusPoints = new StylusPointCollection();
        Point pt = e.GetPosition(this);
        stylusPoints.Add(new StylusPoint(pt.X, pt.Y));

    }

    protected override void OnMouseMove(MouseEventArgs e)
    {

        base.OnMouseMove(e);

        // If a stylus generated this event, return.
        if (e.StylusDevice != null)
        {
            return;
        }

        // Don't collect points unless the left mouse button
        // is down.
        if (e.LeftButton == MouseButtonState.Released || 
            stylusPoints == null)
        {
            return;
        }

        Point pt = e.GetPosition(this);
        stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
    }

    protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
    {

        base.OnMouseLeftButtonUp(e);

        // If a stylus generated this event, return.
        if (e.StylusDevice != null)
        {
            return;
        }

        if (stylusPoints == null)
        {
            return;
        }

        Point pt = e.GetPosition(this);
        stylusPoints.Add(new StylusPoint(pt.X, pt.Y));

        // Create a stroke and add it to the InkPresenter.
        Stroke stroke = new Stroke(stylusPoints);
        stroke.DrawingAttributes = dr.DrawingAttributes;
        ip.Strokes.Add(stroke);

        stylusPoints = null;

    }
}

Utilizzo di plug-in aggiuntivi e oggetti DynamicRenderer

Analogamente agli InkCanvas, il controllo personalizzato può includere un oggetto StylusPlugIn personalizzato e oggetti DynamicRenderer aggiuntivi. Aggiungere questi oggetti all'insieme StylusPlugIns. L'ordine degli oggetti StylusPlugIn nell'insieme StylusPlugInCollection influisce sull'aspetto dell'input penna quando viene sottoposto a rendering. Si supponga di disporre di un oggetto DynamicRenderer denominato dynamicRenderer e di un oggetto StylusPlugIn personalizzato denominato translatePlugin che esegue l'offset dell'input della penna del Tablet PC. Se translatePlugin è il primo oggetto StylusPlugIn nell'insieme StylusPlugInCollection e dynamicRenderer è il secondo, l'input penna che "fluisce" verrà sottoposto a offset mentre l'utente sposta la penna. Se dynamicRenderer è il primo e translatePlugin è il secondo oggetto, l'input penna verrà sottoposto a offset solo quando l'utente solleva la penna.

Conclusione

È possibile creare un controllo che raccoglie l'input penna e lo sottopone a rendering eseguendo l'override dei metodi degli eventi dello stilo. Creando un controllo personalizzato, derivando le classi StylusPlugIn e inserendole nell'insieme StylusPlugInCollection, è possibile implementare di fatto qualsiasi comportamento immaginabile con l'input penna. Ottenendo l'accesso ai dati StylusPoint mentre vengono generati, è possibile personalizzare l'input di Stylus e sottoporlo a rendering sullo schermo nel modo appropriato per l'applicazione. Grazie all'accesso di basso livello ai dati StylusPoint, è possibile implementare la raccolta e il rendering dell'input penna con prestazioni ottimali per l'applicazione.

Vedere anche

Altre risorse

Gestione avanzata dell'input penna

Accesso e modifica dell'input penna