Creazione di un controllo di input penna digitale
È possibile creare un controllo personalizzato che rende l’inchiostro in modo sia dinamico che statico. Ovvero, rendere l'inchiostro mentre l'utente disegna un tratto, facendo apparire l'inchiostro come se "fluisse" dalla penna del tablet, e visualizzare l'inchiostro dopo che è stato aggiunto al controllo, sia tramite la penna del tablet, incollato dagli Appunti o caricato da un file. Per eseguire il rendering dinamico dell'inchiostro, il controllo deve usare un DynamicRenderer. Per eseguire il rendering statico dell'inchiostro, è necessario eseguire l'override dei metodi evento dello stilo (OnStylusDown, OnStylusMovee OnStylusUp) per raccogliere dati StylusPoint, creare tratti e aggiungerli a un InkPresenter (che esegue il rendering dell'inchiostro sul controllo).
Questo argomento contiene le sottosezioni seguenti:
Procedura: Raccogliere dati dei punti dello stilo e creare tratti di inchiostro
Procedura: consentire al tuo controllo di ricevere input dal mouse
Come raccogliere i dati dei punti di penna digitale e creare tratti di inchiostro
Per creare un controllo che raccoglie e gestisce i tratti input penna, eseguire le operazioni seguenti:
Derivare una classe da Control o una delle classi derivate da Control, ad esempio Label.
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 {
}
Aggiungere un InkPresenter alla classe e impostare la proprietà Content sul nuovo InkPresenter.
InkPresenter ip; public InkControl() { // Add an InkPresenter for drawing. ip = new InkPresenter(); this.Content = ip; }
Collegare il RootVisual del DynamicRenderer al InkPresenter chiamando il metodo AttachVisuals e aggiungere il DynamicRenderer all'insieme StylusPlugIns. Ciò consente al InkPresenter di visualizzare l'inchiostro mentre i dati del punto della penna vengono raccolti dal tuo controllo.
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); }
Sovrascrivere il metodo OnStylusDown. Con questo metodo, cattura lo stilo con una chiamata a Capture. Acquisendo la penna, il controllo continuerà a ricevere gli eventi StylusMove e StylusUp anche se la penna esce dai limiti del controllo. Questo non è strettamente obbligatorio, ma quasi sempre desiderato per una buona esperienza utente. Creare una nuova StylusPointCollection per raccogliere dati StylusPoint. Infine, aggiungere il set iniziale di dati StylusPoint al StylusPointCollection.
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); }
Eseguire l'override del metodo OnStylusMove e aggiungere i dati StylusPoint all'oggetto StylusPointCollection creato in precedenza.
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); }
Eseguire l'override del metodo OnStylusUp e creare un nuovo Stroke con i dati StylusPointCollection. Aggiungere la nuova Stroke creata alla raccolta Strokes di InkPresenter e rilasciare l'acquisizione dello stilo.
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 accettare l'input dal mouse
Se si aggiunge il controllo precedente all'applicazione, eseguirlo e usare il mouse come dispositivo di input, noterai che i tratti non sono persistenti. Per rendere persistenti i tratti quando il mouse viene usato come dispositivo di input, eseguire le operazioni seguenti:
Esegui l'override del OnMouseLeftButtonDown e crea un nuovo StylusPointCollection. Ottieni la posizione del mouse quando si è verificato l'evento. Crea un StylusPoint usando i dati del punto e aggiungi il StylusPoint al StylusPointCollection.
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)); }
Sovrascrivere il metodo OnMouseMove. Ottieni la posizione del mouse quando si è verificato l'evento e crea un StylusPoint usando i dati del punto. Aggiungere il StylusPoint all'oggetto StylusPointCollection creato in precedenza.
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)); }
Sovrascrivere il metodo OnMouseLeftButtonUp. Creare un nuovo Stroke con i dati di StylusPointCollection e aggiungere il nuovo Stroke che hai creato alla raccolta Strokes di InkPresenter.
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; }
Mettere tutto insieme
L'esempio seguente è un controllo personalizzato che raccoglie l'inchiostro quando l'utente usa il mouse o la penna.
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;
}
}
Uso di plug-in aggiuntivi e di DynamicRenderers
Analogamente a InkCanvas, il controllo personalizzato può avere StylusPlugIn personalizzati e oggetti DynamicRenderer aggiuntivi. Aggiungerli alla collezione StylusPlugIns. L'ordine degli oggetti StylusPlugIn nel StylusPlugInCollection influisce sull'aspetto dell'inchiostro quando viene effettuato il rendering. Supponiamo di avere un DynamicRenderer denominato dynamicRenderer
e una StylusPlugIn personalizzata denominata translatePlugin
che sposta l'inchiostro dalla penna del tablet. Se translatePlugin
è il primo StylusPlugIn nella StylusPlugInCollectione dynamicRenderer
è il secondo, l'inchiostro che "scorre" verrà sfalsato mentre l'utente muove la penna. Se dynamicRenderer
è primo e translatePlugin
è secondo, l'inchiostro non sarà spostato finché l'utente non solleva la penna.
Conclusione
È possibile creare un controllo che raccoglie e rende l'inchiostro digitale sovrascrivendo i metodi di evento dello stilo. Creando un proprio controllo, derivando le proprie classi StylusPlugIn e inserendole in StylusPlugInCollection, è possibile implementare praticamente qualsiasi comportamento immaginabile con l'inchiostro digitale. È possibile accedere ai dati StylusPoint man mano che viene generato, offrendo la possibilità di personalizzare i dati di input Stylus e visualizzarli sullo schermo in base alle esigenze dell'applicazione. Poiché hai un accesso di basso livello ai dati di StylusPoint, puoi implementare la raccolta di inchiostro ed eseguirne il rendering con prestazioni ottimali per l'applicazione.
Vedere anche
.NET Desktop feedback