Ink 对象模型:Windows 窗体和 COM 与 WPF 之比较

主要有三个支持数字墨迹的平台:Tablet PC Windows 窗体平台、Tablet PC COM 平台和 Windows Presentation Foundation (WPF) 平台。 Windows 窗体平台和 COM 平台的对象模型非常类似,但 WPF 平台的对象模型有根本的不同。 本主题从较高层次讨论其区别,以便只使用一种对象模型的开发人员可以更好地了解其他对象模型。

在应用程序中启用墨迹

所有三个平台都附带了对象和控件,这些对象和控件使应用程序可以接收触笔的输入。 Windows 窗体平台和 COM 平台附带了 InkPicture、InkEdit、InkOverlay 和 InkCollector 类。 InkPicture 和 InkEdit 是可以添加到应用程序中用来收集墨迹的控件。 InkOverlay 和 InkCollector 可以附加到现有的窗口,以便对窗口和自定义控件启用墨迹。

WPF 平台包含 InkCanvas 控件。 可以将 InkCanvas 添加到应用程序中并立即开始收集墨迹。 使用 InkCanvas,用户可以复制、选择墨迹和调整墨迹大小。 也可以将其他控件添加到 InkCanvas,用户可以在这些控件上进行手写。 可以通过将 InkPresenter 添加到自定义控件并收集其触笔接触点,创建支持墨迹的自定义控件。

下表列出了在何处可以了解有关在应用程序中启用墨迹的更多信息:

若要执行此操作...

在 WPF 平台上…

在 Windows 窗体/COM 平台上…

将支持墨迹的控件添加到应用程序中

请参见墨迹入门

请参见Auto Claims Form Sample

在自定义控件上启用墨迹

请参见创建墨迹输入控件

请参见Ink Clipboard Sample

墨迹数据

在 Windows 窗体平台和 COM 平台上,InkCollector、InkOverlay、InkEdit 和 InkPicture 都公开一个 Ink 对象。 Ink 对象包含一个或多个 Stroke 对象的数据,并公开常用方法和属性,以管理和操作这些笔画。 Ink 对象管理所包含笔画的生命周期;Ink 对象创建并删除所拥有的笔画。 每个 Stroke 在其父 Ink 对象中都有一个唯一标识符。

在 WPF 平台上,System.Windows.Ink.Stroke 类拥有并管理自己的生命周期。 可以将一组 Stroke 对象收集到一个 StrokeCollection 中,以提供常用墨迹数据管理操作(如命中测试、擦除、转换和序列化墨迹)方法。 在任意给定时刻,Stroke 可以属于零个、一个或多个 StrokeCollection 对象。 InkCanvasInkPresenter 包含 System.Windows.Ink.StrokeCollection,而不是 Ink 对象。

下面两个插图对墨迹数据对象模型进行了比较。 在 Windows 窗体平台和 COM 平台上,Ink 对象约束 Stroke 对象的生命周期,且触笔数据包属于单个笔画。 如下图所示,两个或更多笔画可以引用同一 DrawingAttributes 对象。

COM/Winforms 墨迹对象模型示意图。

在 WPF 上,每个 System.Windows.Ink.Stroke 都是一个常用语言运行时对象,只要有对象引用就会存在。 每个 Stroke 均引用 StylusPointCollectionSystem.Windows.Ink.DrawingAttributes 对象,这两个对象都是常用语言运行时对象。

WPF 墨迹对象模型示意图。

下表对在 WPF 平台、Windows 窗体平台和 COM 平台上完成某些常用任务的方法进行了比较。

任务

Windows Presentation Foundation

Windows 窗体和 COM

保存墨迹

Save

Save()

加载墨迹

使用 StrokeCollection.StrokeCollection(Stream) 构造函数创建 StrokeCollection

Load(Byte[])

命中测试

HitTest

HitTest()

复制墨迹

CopySelection

ClipboardCopy()

粘贴墨迹

Paste

ClipboardPaste()

访问笔画集合的自定义属性

AddPropertyData(这些属性存储在内部,并通过 AddPropertyDataRemovePropertyDataContainsPropertyData 访问)

使用 ExtendedProperties()

在平台之间共享墨迹

虽然各平台的墨迹数据对象模型不同,但是在各平台之间共享数据却非常简单。 下面的示例保存 Windows 窗体应用程序中的墨迹,并将该墨迹加载到 Windows Presentation Foundation 应用程序。

Imports Microsoft.Ink
Imports System.Drawing


...


'/ <summary>
'/ Saves the digital ink from a Windows Forms application.
'/ </summary>
'/ <param name="inkToSave">An Ink object that contains the 
'/ digital ink.</param>
'/ <returns>A MemoryStream containing the digital ink.</returns>
Function SaveInkInWinforms(ByVal inkToSave As Ink) As MemoryStream 
    Dim savedInk As Byte() = inkToSave.Save()

    Return New MemoryStream(savedInk)

End Function 'SaveInkInWinforms
using Microsoft.Ink;
using System.Drawing;


...


/// <summary>
/// Saves the digital ink from a Windows Forms application.
/// </summary>
/// <param name="inkToSave">An Ink object that contains the 
/// digital ink.</param>
/// <returns>A MemoryStream containing the digital ink.</returns>
MemoryStream SaveInkInWinforms(Ink inkToSave)
{
    byte[] savedInk = inkToSave.Save();

    return (new MemoryStream(savedInk));

}
Imports System.Windows.Ink



...


'/ <summary>
'/ Loads digital ink into a StrokeCollection, which can be 
'/ used by a WPF application.
'/ </summary>
'/ <param name="savedInk">A MemoryStream containing the digital ink.</param>
Public Sub LoadInkInWPF(ByVal inkStream As MemoryStream) 
    strokes = New StrokeCollection(inkStream)

End Sub 'LoadInkInWPF

using System.Windows.Ink;


...


/// <summary>
/// Loads digital ink into a StrokeCollection, which can be 
/// used by a WPF application.
/// </summary>
/// <param name="savedInk">A MemoryStream containing the digital ink.</param>
public void LoadInkInWPF(MemoryStream inkStream)
{
    strokes = new StrokeCollection(inkStream);
}

下面的示例保存 Windows Presentation Foundation 应用程序中的墨迹,并将该墨迹加载到 Windows 窗体应用程序。

Imports System.Windows.Ink



...


'/ <summary>
'/ Saves the digital ink from a WPF application.
'/ </summary>
'/ <param name="inkToSave">A StrokeCollection that contains the 
'/ digital ink.</param>
'/ <returns>A MemoryStream containing the digital ink.</returns>
Function SaveInkInWPF(ByVal strokesToSave As StrokeCollection) As MemoryStream 
    Dim savedInk As New MemoryStream()

    strokesToSave.Save(savedInk)

    Return savedInk

End Function 'SaveInkInWPF

using System.Windows.Ink;


...


/// <summary>
/// Saves the digital ink from a WPF application.
/// </summary>
/// <param name="inkToSave">A StrokeCollection that contains the 
/// digital ink.</param>
/// <returns>A MemoryStream containing the digital ink.</returns>
MemoryStream SaveInkInWPF(StrokeCollection strokesToSave)
{
    MemoryStream savedInk = new MemoryStream();

    strokesToSave.Save(savedInk);

    return savedInk;
}
Imports Microsoft.Ink
Imports System.Drawing


...


'/ <summary>
'/ Loads digital ink into a Windows Forms application.
'/ </summary>
'/ <param name="savedInk">A MemoryStream containing the digital ink.</param>
Public Sub LoadInkInWinforms(ByVal savedInk As MemoryStream) 
    theInk = New Ink()
    theInk.Load(savedInk.ToArray())

End Sub 'LoadInkInWinforms
using Microsoft.Ink;
using System.Drawing;


...


/// <summary>
/// Loads digital ink into a Windows Forms application.
/// </summary>
/// <param name="savedInk">A MemoryStream containing the digital ink.</param>
public void LoadInkInWinforms(MemoryStream savedInk)
{
    theInk = new Ink();
    theInk.Load(savedInk.ToArray());
}

触笔的事件

Windows 窗体平台和 COM 平台上的 InkOverlay、InkCollector 和 InkPicture 在用户输入笔数据时接收事件。 InkOverlay 或 InkCollector 附加到窗口或控件中,可以订阅由 Tablet 输入数据引发的事件。 这些事件发生时所在的线程取决于该事件是由笔、鼠标还是以编程方式引发。 有关与这些事件相关的线程的更多信息,请参见General Threading ConsiderationsThreads on Which an Event Can Fire

在 Windows Presentation Foundation 平台上,UIElement 类具有笔输入事件。 这意味着每个控件都公开完整的触笔事件集。 触笔事件具有隧道/冒泡事件对,并始终发生于应用程序线程上。 有关更多信息,请参见路由事件概述

下图对引发触笔事件的类的对象模型进行了比较。 Windows Presentation Foundation 对象模型只显示冒泡事件,不显示对应的隧道事件。

WPF 与 Winforms 中的触笔事件对比示意图。

笔数据

所有三个平台都为您提供了截获和操作来自触笔的数据的方法。 在 Windows 窗体平台和 COM 平台上,这通过创建一个 RealTimeStylus、为其附加窗口或控件并创建实现 IStylusSyncPlugin 或 IStylusAsyncPlugin 接口的类来完成。 随后,将自定义插件添加到 RealTimeStylus 的插件集合中。 有关此对象模型的更多信息,请参见 Architecture of the StylusInput APIs

在 WPF 平台上,UIElement 类公开一个插件集合,在设计上类似于 RealTimeStylus。 若要截获笔数据,请创建一个从 StylusPlugIn 继承的类,并将该对象添加到 UIElementStylusPlugIns 集合中。 有关此交互的更多信息,请参见截获触笔输入

在所有平台上,线程池通过触笔事件接收墨迹数据,并将其发送到应用程序线程。 有关 COM 和 Windows 平台上线程处理的更多信息,请参见 Threading Considerations for the StylusInput APIs。 有关 Windows Presentation 软件上线程处理的更多信息,请参见 墨迹线程处理模型

下图对接收笔线程池中的笔数据的类的对象模型进行了比较。

WPF 与 Winforms 中的 StylusPlugin 模型对比示意图。