System.Windows.Input.StylusPlugIns 体系结构提供了一种机制,用于实现对 Stylus 输入的低级别控制以及创建数字墨迹 Stroke 对象。 StylusPlugIn 类提供了一种机制,用于实现自定义行为并将其应用于来自触笔设备的数据流,以实现最佳性能。
本主题包含以下小节:
建筑
StylusPlugIn 是 触笔输入 API 的演变,如《访问和操作笔输入》中所述。
每个 UIElement 都有一个 StylusPlugIns 属性,该属性是 StylusPlugInCollection。 可以向元素的 StylusPlugIn 属性添加 StylusPlugIns,以在生成 StylusPoint 数据时操作该数据。 StylusPoint 数据包括系统数字化器支持的所有属性,包括 X 和 Y 点数据,以及 PressureFactor 数据。
当您向 StylusPlugIn 属性添加 Stylus 时,StylusPlugIn 对象会直接插入来自 StylusPlugIns 设备的数据流中。 将插件添加到 StylusPlugIns 集合的顺序决定了它们接收 StylusPoint 数据的顺序。 例如,如果添加一个将输入限制为特定区域的筛选器插件,然后添加一个在写入内容时识别手势的插件,则识别手势的插件将收到筛选的 StylusPoint 数据。
实现触笔插件
若要实现插件,请从 StylusPlugIn派生一个类。 此类应用于数据流,因为它来自 Stylus。 在此类中,可以修改 StylusPoint 数据的值。
谨慎
如果 StylusPlugIn 引发或导致异常,应用程序将关闭。 如果确定 StylusPlugIn 不会引发异常,则应彻底测试使用 StylusPlugIn 的控件且仅使用控件。
以下示例演示了一个插件,该插件通过修改来自 X 设备的 Y 数据中的 StylusPoint 和 Stylus 值来限制触笔输入。
using System;
using System.Windows.Media;
using System.Windows;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Input;
using System.Windows.Ink;
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 : 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);
    }
}
' 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
    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
    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
    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
End Class
将插件添加到 InkCanvas
使用自定义插件的最简单方法是实现派生自 InkCanvas 的类,并将其添加到 StylusPlugIns 属性。
以下示例演示筛选墨迹的自定义 InkCanvas。
public class FilterInkCanvas : InkCanvas
{
    FilterPlugin filter = new FilterPlugin();
    public FilterInkCanvas()
        : base()
    {
        this.StylusPlugIns.Add(filter);
    }
}
如果将 FilterInkCanvas 添加到应用程序并运行,你会注意到,墨迹不会在用户完成笔划之前限制在特定区域内。 这是因为 InkCanvas 具有 DynamicRenderer 属性,该属性是 StylusPlugIn,并且已是 StylusPlugIns 集合的成员。 添加到 StylusPlugIn 集合的自定义 StylusPlugIns 在 StylusPoint 接收数据后接收 DynamicRenderer 数据。 因此,只有在用户抬起笔以结束笔划后才会筛选 StylusPoint 数据。 若要在用户绘制墨迹时筛选墨迹,必须在 FilterPlugin 之前插入 DynamicRenderer。
以下 C# 代码演示了一个自定义 InkCanvas,用于在绘制墨迹时筛选墨迹。
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 数据具有如此低级别的访问权限,因此可以为您的应用程序以最佳性能实现墨迹收集和呈现。