基本上有三个平台支持数字墨迹:平板电脑 Windows 窗体平台、平板电脑 COM 平台和 Windows Presentation Foundation (WPF) 平台。 Windows 窗体和 COM 平台共享类似的对象模型,但 WPF 平台的对象模型大相径庭。 本主题讨论高级别的差异,以便使用一个对象模型的开发人员可以更好地了解另一个对象模型。
在应用程序中启用墨迹
所有三个平台都提供对象和控制,使应用程序能够从平板电脑笔接收输入。 Windows 窗体和 COM 平台附带 Microsoft.Ink.InkPicture、Microsoft.Ink.InkEdit、Microsoft.Ink.InkOverlay 和 Microsoft.Ink.InkCollector 类。 Microsoft.Ink.InkPicture 和 Microsoft.Ink.InkEdit 是可以添加到应用程序以收集墨迹的控件。 Microsoft.Ink.InkOverlay 和 Microsoft.Ink.InkCollector 可以附加到现有的窗口上,以使窗口和自定义控件支持墨迹功能。
WPF 平台包括 InkCanvas 控件。 可以向应用程序添加 InkCanvas,然后立即开始收集墨迹。 使用 InkCanvas,用户可以复制、选择和调整墨迹大小。 你可向 InkCanvas 添加其他控件,用户也可在这些控件上手写。 可以通过向其添加 InkPresenter 并收集其触笔点来创建启用墨迹的自定义控件。
下表列出了在应用程序中启用墨迹的详细信息:
要执行此操作 ... | 在 WPF 平台上… | 在 Windows 窗体/COM 平台上… |
---|---|---|
向应用程序添加启用墨迹的控件 | 请参阅墨迹入门。 | 请参阅 自动声明表单示例 |
在自定义控件上启用墨迹 | 请参阅创建墨迹输入控件。 | 请参阅 墨水剪贴板示例。 |
墨水数据
在 Windows 窗体和 COM 平台上,Microsoft.Ink.InkCollector、Microsoft.Ink.InkOverlay、Microsoft.Ink.InkEdit,Microsoft.Ink.InkPicture 分别公开 Microsoft.Ink.Ink 对象。 Microsoft.Ink.Ink 对象包含一个或多个 Microsoft.Ink.Stroke 对象的数据,并公开用于管理和操作这些笔划的常用方法和属性。 Microsoft.Ink.Ink 对象管理其包含的笔划的生存期;Microsoft.Ink.Ink 对象创建并删除其拥有的笔划。 每个 Microsoft.Ink.Stroke 的标识符在其父 Microsoft.Ink.Ink 对象中是唯一的。
在 WPF 平台上,System.Windows.Ink.Stroke 类拥有和管理其自己的生存期。 一组 Stroke 对象可以一起收集在 StrokeCollection 中,它提供常见的墨迹数据管理操作方法,例如命中测试、擦除、转换和序列化墨迹。 在任何给定时间,Stroke 都可以属于零个、一个或多个 StrokeCollection 对象。 和 InkCanvas 包含的不是 InkPresenter 对象,而是 System.Windows.Ink.StrokeCollection。
以下一对插图比较了墨迹数据对象模型。 在 Windows 窗体和 COM 平台上,Microsoft.Ink.Ink 对象约束 Microsoft.Ink.Stroke 对象的生存期,而触笔数据包属于各个笔划。 两个或更多笔划可以引用相同的 Microsoft.Ink.DrawingAttributes 对象,如下图所示。
在 WPF 上,每个 System.Windows.Ink.Stroke 都是一个公共语言运行时对象,只要某些内容引用了该对象,该对象就会存在。 每个 Stroke 都引用一个 StylusPointCollection 和 System.Windows.Ink.DrawingAttributes 对象,该对象也是公共语言运行时对象。
下表比较了如何在 WPF 平台和 Windows 窗体和 COM 平台上完成一些常见任务。
任务 | Windows Presentation Foundation | Windows 窗体和 COM |
---|---|---|
节约墨水 | Save | Microsoft.Ink.Ink.Save |
加载墨迹 | 使用 StrokeCollection 构造函数创建一个 StrokeCollection。 | Microsoft.Ink.Ink.Load |
命中测试 | HitTest | Microsoft.Ink.Ink.HitTest |
复制墨迹 | CopySelection | Microsoft.Ink.Ink.ClipboardCopy |
粘贴墨迹 | Paste | Microsoft.Ink.Ink.ClipboardPaste |
访问笔划集合的自定义属性 | AddPropertyData(属性在内部通过 AddPropertyData、RemovePropertyData和 ContainsPropertyData进行存储和访问) | 使用 Microsoft.Ink.Ink.ExtendedProperties |
在平台之间共享墨迹
尽管平台具有不同的墨迹数据对象模型,但平台之间共享数据非常简单。 以下示例将墨迹从 Windows 窗体应用程序保存,并将墨迹加载到 Windows Presentation Foundation 应用程序中。
using Microsoft.Ink;
using System.Drawing;
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>
MemoryStream SaveInkInWinforms(Ink inkToSave)
{
byte[] savedInk = inkToSave.Save();
return (new MemoryStream(savedInk));
}
'/ <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 System.Windows.Ink;
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 void LoadInkInWPF(MemoryStream inkStream)
{
strokes = new StrokeCollection(inkStream);
}
'/ <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
以下示例将墨迹从 Windows Presentation Foundation 应用程序保存,并将墨迹加载到 Windows 窗体应用程序中。
using System.Windows.Ink;
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>
MemoryStream SaveInkInWPF(StrokeCollection strokesToSave)
{
MemoryStream savedInk = new MemoryStream();
strokesToSave.Save(savedInk);
return savedInk;
}
'/ <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 Microsoft.Ink;
using System.Drawing;
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 void LoadInkInWinforms(MemoryStream savedInk)
{
theInk = new Ink();
theInk.Load(savedInk.ToArray());
}
'/ <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
来自触笔的事件
Microsoft.Ink.InkOverlay、Microsoft.Ink.InkCollector和 Microsoft.Ink.InkPicture 在 Windows 窗体和 COM 平台上接收用户输入笔数据时的事件。 Microsoft.Ink.InkOverlay 或 Microsoft.Ink.InkCollector 附加到窗口或控件,并且可以订阅触笔输入数据引发的事件。 发生这些事件的线程取决于是用笔、鼠标还是以编程方式引发事件。 有关与这些事件相关的线程处理的详细信息,请参阅常规线程处理注意事项和可以触发事件的线程。
在 Windows Presentation Foundation 平台上,UIElement 类具有用于笔输入的事件。 这意味着每个控件都会公开完整的触笔事件集。 触笔事件具有隧道/浮升事件对,并且始终出现在应用程序线程上。 有关详细信息,请参阅 路由事件概述。
下图显示了对引发触笔事件的类的对象模型进行比较。 Windows Presentation Foundation 对象模型仅显示浮泡事件,而不是隧道事件对应项。
触笔数据
这三个平台都为你提供了截获和操作来自平板电脑笔的数据的方法。 在 Windows 窗体和 COM 平台上,这是通过创建 Microsoft.StylusInput.RealTimeStylus、将窗口或控件附加到它上面,并创建一个实现 Microsoft.StylusInput.IStylusSyncPlugin 或 Microsoft.StylusInput.IStylusAsyncPlugin 接口的类来达成。 然后将自定义插件添加到 Microsoft.StylusInput.RealTimeStylus的插件集合中。 有关此对象模型的详细信息,请参阅 StylusInput API 的体系结构。
在 WPF 平台上,UIElement 类公开插件集合,类似于 Microsoft.StylusInput.RealTimeStylus的设计。 若要截获笔数据,请创建一个从 StylusPlugIn 继承的类,并将对象添加到 StylusPlugIns的 UIElement 集合中。 有关此交互的详细信息,请参阅截获触笔的输入。
在所有平台上,线程池通过触笔事件接收墨迹数据,并将其发送到应用程序线程。 有关 COM 和 Windows 平台上的线程处理的详细信息,请参阅 触笔输入 API 的线程处理注意事项。 有关 Windows 演示文稿软件上的线程的详细信息,请参阅 墨迹线程模型。
下图比较了在触笔线程池上接收触笔数据的类的对象模型。