创建墨迹输入控件
可以创建动态和静态呈现墨迹的自定义控件。 也就是说,当用户绘制笔划时呈现墨迹,使墨迹看起来从平板电脑笔中“流出”,并在墨迹被添加到控件后显示,无论是通过平板电脑笔、从剪贴板粘贴还是从文件加载。 若要动态呈现墨迹,控件必须使用 DynamicRenderer标识符。 若要静态渲染墨迹,必须重写触笔事件方法(OnStylusDown、OnStylusMove和 OnStylusUp),以收集 StylusPoint 数据、创建笔划,并将其添加到 InkPresenter(将墨迹呈现在控件上)。
本主题包含以下小节:
如何:收集触笔点数据并创建墨迹笔划
若要创建收集和管理墨迹笔划的控件,请执行以下操作:
从 Control 派生一个类或从 Control派生的类之一,例如 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 {
}
向类添加 InkPresenter,并将 Content 属性设置为新的 InkPresenter。
InkPresenter ip; public InkControl() { // Add an InkPresenter for drawing. ip = new InkPresenter(); this.Content = ip; }
通过调用 AttachVisuals 方法将 DynamicRenderer 的 RootVisual 附加到 InkPresenter,并将 DynamicRenderer 添加到 StylusPlugIns 集合。 这样,InkPresenter 就可以在控件收集触笔点数据时显示墨迹。
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); }
重写 OnStylusDown 方法。 在此方法中,通过调用 Capture来捕获触笔。 通过捕获触笔,你的控件将继续接收 StylusMove 和 StylusUp 事件,即使触笔离开控件的边界。 这不是严格强制性的,但几乎总是需要良好的用户体验。 创建新的 StylusPointCollection 以收集 StylusPoint 数据。 最后,将初始 StylusPoint 数据集添加到 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); }
重写 OnStylusMove 方法,并将 StylusPoint 数据添加到之前创建的 StylusPointCollection 对象。
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); }
重写 OnStylusUp 方法,并使用 StylusPointCollection 数据创建新的 Stroke。 将您创建的新 Stroke 添加到 InkPresenter 的 Strokes 集合中,并释放触控笔捕获。
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); }
如何:使控件能够接受鼠标输入
如果将上述控件添加到应用程序,请运行它并使用鼠标作为输入设备,你会注意到笔划不会持久保存。 若要在鼠标用作输入设备时保留笔划,请执行以下操作:
重写 OnMouseLeftButtonDown 并创建新的 StylusPointCollection 获取事件发生时鼠标的位置,并使用点数据创建 StylusPoint,并将 StylusPoint 添加到 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)); }
重写 OnMouseMove 方法。 获取事件发生时鼠标的位置,并使用点数据创建 StylusPoint。 将 StylusPoint 添加到之前创建的 StylusPointCollection 对象。
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)); }
重写 OnMouseLeftButtonUp 方法。 使用 StylusPointCollection 数据创建新的 Stroke,并将创建的新 Stroke 添加到 InkPresenter的 Strokes 集合中。
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; }
把它放在一起
以下示例是当用户使用鼠标或笔时收集墨迹的自定义控件。
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;
}
}
使用其他插件和“DynamicRenderers”
与 InkCanvas 一样,您的自定义控件可以具备自定义的 StylusPlugIn 和其他 DynamicRenderer 对象。 将这些内容添加到 StylusPlugIns 集合。 StylusPlugInCollection 中 StylusPlugIn 对象的顺序会影响墨迹显示时的外观。 假设你有一个名为 dynamicRenderer
的 DynamicRenderer 和一个名为 translatePlugin
的自定义 StylusPlugIn,其中 translatePlugin
用于调整从平板电脑笔中释放的墨迹。 如果 translatePlugin
是 StylusPlugInCollection中的第一个 StylusPlugIn,dynamicRenderer
是第二个,那么当用户移动笔时,“流”的墨迹将会偏移。 如果 dynamicRenderer
是第一个,并且 translatePlugin
为第二个,则在用户抬起笔之前,墨迹不会偏移。
结论
您可以通过重写触笔事件方法来创建一个控件,以收集和显示墨迹。 通过创建自定义控件、派生自己的 StylusPlugIn 类并将其插入到 StylusPlugInCollection中,您几乎可以实现各种可以用数字墨水设想的行为。 你可以访问生成的 StylusPoint 数据,从而有机会根据应用程序自定义 Stylus 输入并将其呈现在屏幕上。 由于对 StylusPoint 数据具有如此低级别的访问权限,因此你可以实现墨迹收集,并为应用程序呈现其最佳性能。