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

更新:2007 年 11 月

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

在应用程序中启用墨迹

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

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

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

若要执行此操作...

在 WPF 平台上…

在 Windows 窗体/COM 平台上…

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

请参见墨迹入门

请参见Auto Claims Form Sample

在自定义控件上启用墨迹

请参见创建墨迹输入控件

请参见Ink Clipboard Sample

墨迹数据

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

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

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

命中测试

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());
}

Tablet 笔的事件

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

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

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

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

笔数据

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

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

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

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

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