截获触笔输入

System.Windows.Input.StylusPlugIns 体系结构提供了一种机制,用于实现对 Stylus 输入的低级别控制以及创建数字墨迹 Stroke 对象。 StylusPlugIn 类提供了一种机制,用于实现自定义行为并将其应用于来自触笔设备的数据流,以实现最佳性能。

本主题包含以下小节:

建筑

StylusPlugIn触笔输入 API 的演变,如《访问和操作笔输入》中所述。

每个 UIElement 都有一个 StylusPlugIns 属性,该属性是 StylusPlugInCollection。 可以向元素的 StylusPlugIns 属性添加 StylusPlugIn,以在生成 StylusPoint 数据时操作该数据。 StylusPoint 数据包括系统数字化器支持的所有属性,包括 XY 点数据,以及 PressureFactor 数据。

当您向 StylusPlugIns 属性添加 StylusPlugIn 时,StylusPlugIn 对象会直接插入来自 Stylus 设备的数据流中。 将插件添加到 StylusPlugIns 集合的顺序决定了它们接收 StylusPoint 数据的顺序。 例如,如果添加一个将输入限制为特定区域的筛选器插件,然后添加一个在写入内容时识别手势的插件,则识别手势的插件将收到筛选的 StylusPoint 数据。

实现触笔插件

若要实现插件,请从 StylusPlugIn派生一个类。 此类应用于数据流,因为它来自 Stylus。 在此类中,可以修改 StylusPoint 数据的值。

谨慎

如果 StylusPlugIn 引发或导致异常,应用程序将关闭。 如果确定 StylusPlugIn 不会引发异常,则应彻底测试使用 StylusPlugIn 的控件且仅使用控件。

以下示例演示了一个插件,该插件通过修改来自 Stylus 设备的 StylusPoint 数据中的 XY 值来限制触笔输入。

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 集合的成员。 添加到 StylusPlugIns 集合的自定义 StylusPlugInDynamicRenderer 接收数据后接收 StylusPoint 数据。 因此,只有在用户抬起笔以结束笔划后才会筛选 StylusPoint 数据。 若要在用户绘制墨迹时筛选墨迹,必须在 DynamicRenderer 之前插入 FilterPlugin

以下 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 数据具有如此低级别的访问权限,因此可以为您的应用程序以最佳性能实现墨迹收集和呈现。

另请参阅