截获触笔输入

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

本主题包含以下小节:

体系结构

StylusPlugInStylusInput API 的演化结果,如访问和处理触笔输入中所述。

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

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

实现触笔插件

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

注意

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

以下示例演示了一个插件,该插件可以在 StylusPoint 数据从 Stylus 设备传入时修改该数据中的 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 并运行它,你会注意到,在用户完成笔划之前,墨迹不会限制到某个区域。 这是因为 InkCanvasDynamicRenderer 属性是 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 数据的访问权限非常低,因此可以使用应用程序的最佳性能实现墨迹收集和呈现。

另请参阅