Criando um controle de entrada de tinta
Você pode criar um controle personalizado que renderiza a tinta de forma dinâmica e estática. Ou seja, é possível renderizar a tinta conforme um usuário desenha um traço, fazendo com que a tinta apareça "fluindo" da caneta eletrônica e exibi-la depois de adicionada ao controle, tanto pela caneta eletrônica, colada da área de transferência ou carregada de um arquivo. Para renderizar tinta dinamicamente, seu controle deve usar um DynamicRendererarquivo . Para renderizar tinta estaticamente, você deve substituir os métodos de evento stylus (, OnStylusMovee ) para coletar StylusPoint dados, criar traçados e OnStylusUpadicioná-los a um InkPresenter (OnStylusDownque renderiza a tinta no controle).
Este tópico contém as seguintes subseções:
Como coletar dados de ponto da caneta e criar traços de tinta
Para criar um controle que coleta e gerencia traços de tinta, faça o seguinte:
Derive uma classe de Control ou uma das classes derivadas de Control, como 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 {
}
Adicione um InkPresenter à classe e defina a Content propriedade como o novo InkPresenter.
InkPresenter ip; public InkControl() { // Add an InkPresenter for drawing. ip = new InkPresenter(); this.Content = ip; }
Anexe DynamicRenderer o de ao InkPresenter chamando o método e adicione o AttachVisualsRootVisualDynamicRenderer à StylusPlugIns coleção. Isso permite que a tinta exiba a InkPresenter tinta à medida que os dados do ponto da caneta são coletados pelo seu controle.
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); }
Substitua o método OnStylusDown. Nesse método, capture a caneta com uma chamada para Capture. Ao capturar a caneta, seu controle continuará a receber StylusMove e StylusUp eventos, mesmo que a caneta saia dos limites do controle. Isso não é estritamente obrigatório, mas quase sempre desejado para uma boa experiência do usuário. Crie um novo StylusPointCollection para coletar StylusPoint dados. Finalmente, adicione o conjunto inicial de StylusPoint dados ao 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); }
Substitua o OnStylusMove método e adicione os StylusPoint dados ao StylusPointCollection objeto que você criou anteriormente.
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); }
Substitua o OnStylusUp método e crie um novo Stroke com os StylusPointCollection dados. Adicione o novo Stroke que você criou à Strokes coleção da captura da InkPresenter caneta e libere.
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); }
Como habilitar o controle para aceitar a entrada do mouse
Se você adicionar o controle anterior ao seu aplicativo, executá-lo e usar o mouse como um dispositivo de entrada, você notará que os traços não serão preservados. Para manter os traços quando o mouse for usado como o dispositivo de entrada, faça o seguinte:
Substitua o e crie um novo StylusPointCollection Obtenha a posição do mouse quando o evento ocorreu e crie um StylusPoint usando os dados de ponto e adicione o StylusPointCollectionOnMouseLeftButtonDownStylusPoint ao .
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)); }
Substitua o método OnMouseMove. Obtenha a posição do mouse quando o evento ocorreu e crie um StylusPoint usando os dados do ponto. Adicione o StylusPoint ao StylusPointCollection objeto que você criou anteriormente.
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)); }
Substitua o método OnMouseLeftButtonUp. Crie um novo com os StylusPointCollection dados e adicione o novo StrokeStroke criado à Strokes coleção do 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; }
Juntando as peças
O exemplo a seguir é um controle personalizado que coleta tinta quando o usuário utiliza o mouse ou a caneta.
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;
}
}
Usando plug-ins adicionais e o DynamicRenderers
Como o InkCanvas, seu controle personalizado pode ter objetos personalizados StylusPlugIn e adicionais DynamicRenderer . Adicione-os à StylusPlugIns coleção. A ordem dos StylusPlugIn objetos no StylusPlugInCollection afeta a aparência da tinta quando ela é renderizada. Suponha que você tenha uma chamada e uma DynamicRenderer chamada translatePlugin
dynamicRenderer
personalizada StylusPlugIn que desligue a tinta da caneta eletrônica. Se translatePlugin
for o primeiro StylusPlugIn no StylusPlugInCollection, e dynamicRenderer
for o segundo, a tinta que "flui" será deslocada à medida que o usuário move a caneta. Se dynamicRenderer
for primeiro e translatePlugin
for o segundo, a tinta não será deslocada até que o usuário levante a caneta.
Conclusão
Você pode criar um controle que coleta e renderiza a tinta, substituindo os métodos de evento da caneta. Ao criar seu próprio controle, derivar suas próprias StylusPlugIn classes e inseri-las no StylusPlugInCollection, você pode implementar praticamente qualquer comportamento imaginável com tinta digital. Você tem acesso aos StylusPoint dados à medida que são gerados, dando-lhe a oportunidade de personalizar Stylus a entrada e renderizá-los na tela conforme apropriado para seu aplicativo. Como você tem acesso de baixo nível aos dados, pode implementar a StylusPoint coleta de tinta e renderizá-la com o desempenho ideal para seu aplicativo.
Confira também
.NET Desktop feedback