更新:2007 年 11 月
System.Windows.Input.StylusPlugIns 体系结构提供了一种机制,用于对 Stylus 输入和数字墨迹 Stroke 对象的创建实现低级别控制。StylusPlugIn 类提供了一种机制,用于实现自定义行为并将其应用于来自手写笔设备的数据流以获得最佳性能。
本主题包含以下小节:
体系结构
实现手写笔插件
将插件添加到 InkCanvas
结束语
体系结构
StylusPlugIn 是在 Microsoft Windows XP Tablet PC Edition Software Development Kit 1.7(Microsoft Windows XP Tablet PC Edition 软件开发工具包 1.7)中的 StylusInput API 的基础上发展而来,Accessing and Manipulating Pen Input(访问和处理笔输入)中对此 API 进行了描述。
每个 UIElement 都有一个属于 StylusPlugInCollection 的 StylusPlugIns 属性。您可以将 StylusPlugIn 添加到元素的 StylusPlugIns 属性,以在生成 StylusPoint 数据时对其进行处理。StylusPoint 数据由系统数字化器支持的所有属性组成,其中包括 X 和 Y 点数据以及 PressureFactor 数据。
将 StylusPlugIn 添加到 StylusPlugIns 属性时,会将 StylusPlugIn 对象直接插入到来自 Stylus 设备的数据流中。将插件添加到 StylusPlugIns 集合的顺序指定了这些插件接收 StylusPoint 数据的顺序。例如,如果添加一个对特定区域的输入加以限制的筛选器插件,然后添加一个识别书写笔势的插件,则识别笔势的插件将接收经过筛选的 StylusPoint 数据。
实现手写笔插件
若要实现插件,请从 StylusPlugIn 中派生一个类。该类在数据流从 Stylus 进入时应用于数据流。在这个类中,您可以修改 StylusPoint 数据的值。
![]() |
---|
如果 StylusPlugIn 引发或导致异常,应用程序将关闭。您应对使用 StylusPlugIn 的控件进行全面测试,并且仅在确信 StylusPlugIn 将不会引发异常时才使用控件。 |
下面的示例演示一个对手写笔输入加以限制的插件,该示例在 StylusPoint 数据从 Stylus 设备进入时修改数据中的 X 和 Y 值。
Imports System
Imports System.Windows.Media
Imports System.Windows
Imports System.Windows.Input.StylusPlugIns
Imports System.Windows.Input
Imports System.Windows.Ink
...
' A StylusPlugin that restricts the input area.
Class FilterPlugin
Inherits StylusPlugIn
Protected Overrides Sub OnStylusDown(ByVal rawStylusInput As RawStylusInput)
' Call the base class before modifying the data.
MyBase.OnStylusDown(rawStylusInput)
' Restrict the stylus input.
Filter(rawStylusInput)
End Sub 'OnStylusDown
Protected Overrides Sub OnStylusMove(ByVal rawStylusInput As RawStylusInput)
' Call the base class before modifying the data.
MyBase.OnStylusMove(rawStylusInput)
' Restrict the stylus input.
Filter(rawStylusInput)
End Sub 'OnStylusMove
Protected Overrides Sub OnStylusUp(ByVal rawStylusInput As RawStylusInput)
' Call the base class before modifying the data.
MyBase.OnStylusUp(rawStylusInput)
' Restrict the stylus input
Filter(rawStylusInput)
End Sub 'OnStylusUp
Private Sub Filter(ByVal rawStylusInput As RawStylusInput)
' Get the StylusPoints that have come in.
Dim stylusPoints As StylusPointCollection = rawStylusInput.GetStylusPoints()
' Modify the (X,Y) data to move the points
' inside the acceptable input area, if necessary.
Dim i As Integer
For i = 0 To stylusPoints.Count - 1
Dim sp As StylusPoint = stylusPoints(i)
If sp.X < 50 Then
sp.X = 50
End If
If sp.X > 250 Then
sp.X = 250
End If
If sp.Y < 50 Then
sp.Y = 50
End If
If sp.Y > 250 Then
sp.Y = 250
End If
stylusPoints(i) = sp
Next i
' Copy the modified StylusPoints back to the RawStylusInput.
rawStylusInput.SetStylusPoints(stylusPoints)
End Sub 'Filter
End Class 'FilterPlugin
using System;
using System.Windows.Media;
using System.Windows;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Input;
using System.Windows.Ink;
...
// A StylusPlugin that restricts the input area.
class FilterPlugin : StylusPlugIn
{
protected override void OnStylusDown(RawStylusInput rawStylusInput)
{
// Call the base class before modifying the data.
base.OnStylusDown(rawStylusInput);
// Restrict the stylus input.
Filter(rawStylusInput);
}
protected override void OnStylusMove(RawStylusInput rawStylusInput)
{
// Call the base class before modifying the data.
base.OnStylusMove(rawStylusInput);
// Restrict the stylus input.
Filter(rawStylusInput);
}
protected override void OnStylusUp(RawStylusInput rawStylusInput)
{
// Call the base class before modifying the data.
base.OnStylusUp(rawStylusInput);
// Restrict the stylus input
Filter(rawStylusInput);
}
private void Filter(RawStylusInput rawStylusInput)
{
// Get the StylusPoints that have come in.
StylusPointCollection stylusPoints = rawStylusInput.GetStylusPoints();
// Modify the (X,Y) data to move the points
// inside the acceptable input area, if necessary.
for (int i = 0; i < stylusPoints.Count; i++)
{
StylusPoint sp = stylusPoints[i];
if (sp.X < 50) sp.X = 50;
if (sp.X > 250) sp.X = 250;
if (sp.Y < 50) sp.Y = 50;
if (sp.Y > 250) sp.Y = 250;
stylusPoints[i] = sp;
}
// Copy the modified StylusPoints back to the RawStylusInput.
rawStylusInput.SetStylusPoints(stylusPoints);
}
}
将插件添加到 InkCanvas
使用自定义插件的最简单途径是实现一个从 InkCanvas 中派生的类,并将其添加到 StylusPlugIns 属性。
下面的示例演示一个对墨迹进行筛选的自定义 InkCanvas。
Public Class FilterInkCanvas
Inherits InkCanvas
Private filter As New FilterPlugin()
Public Sub New()
Me.StylusPlugIns.Add(filter)
End Sub 'New
End Class 'FilterInkCanvas
public class FilterInkCanvas : InkCanvas
{
FilterPlugin filter = new FilterPlugin();
public FilterInkCanvas()
: base()
{
this.StylusPlugIns.Add(filter);
}
}
如果将 FilterInkCanvas 添加到应用程序并运行,您将注意到在用户写完笔划之前,墨迹不会被限制在某个区域中。这是因为 InkCanvas 具有 DynamicRenderer 属性,该属性是 StylusPlugIn,并且已经是 StylusPlugIns 集合的成员。您添加到 StylusPlugIns 集合的自定义 StylusPlugIn 在 DynamicRenderer 接收数据后接收 StylusPoint 数据。因此,在用户提起笔结束笔画之前,将不会对 StylusPoint 数据进行筛选。若要在用户写出墨迹时对墨迹进行筛选,您必须在 DynamicRenderer 之前插入 FilterPlugin。
下面的 C# 代码演示一个在写出墨迹时对墨迹进行筛选的自定义 InkCanvas。
Public Class DynamicallyFilteredInkCanvas
Inherits InkCanvas
Private filter As New FilterPlugin()
Public Sub New()
Dim dynamicRenderIndex As Integer = Me.StylusPlugIns.IndexOf(Me.DynamicRenderer)
Me.StylusPlugIns.Insert(dynamicRenderIndex, filter)
End Sub 'New
End Class 'DynamicallyFilteredInkCanvas
public class DynamicallyFilteredInkCanvas : InkCanvas
{
FilterPlugin filter = new FilterPlugin();
public DynamicallyFilteredInkCanvas()
: base()
{
int dynamicRenderIndex =
this.StylusPlugIns.IndexOf(this.DynamicRenderer);
this.StylusPlugIns.Insert(dynamicRenderIndex, filter);
}
}
结束语
通过派生您自己的 StylusPlugIn 类并将这些类插入 StylusPlugInCollection 集合,您可以极大改进数字墨迹的行为。您可以在 StylusPoint 数据生成时对其进行访问,从而能够自定义 Stylus 输入。由于能够对 StylusPoint 数据进行这种低级别访问,因此,您可以实现墨迹收集和呈现的同时获得应用程序的最佳性能。