使用托管库

公共语言运行时是 Microsoft .NET Framework的基础。 可以将公共语言运行时视为在执行时管理代码的代理,提供核心服务(如内存管理、线程管理和远程处理),同时强制实施严格的代码安全。 事实上,代码管理的概念是公共语言运行时的基本原则。 面向公共语言运行时的代码称为托管代码。 不面向公共语言运行时的代码称为本机代码。

Framework 类库是一个全面的面向对象的可重用类集合,可用于开发各种应用程序,从传统的命令行或图形用户界面 (GUI) 应用程序,到基于 ASP.NET 和 Web 服务提供的最新创新的应用程序。

Tablet PC 托管库包含一组托管对象,这些对象扩展了框架,以提供对平板电脑上手写的输入和输出以及与其他计算机的数据交换的支持。

异常

Tablet PC API 中的托管库对象包装 COM 库实现。 当基础 COM 库对象或控件返回错误时,托管 API 的 将引发 Marshal.ThrowExceptionForHR 异常,该异常提供有关内部 COM 异常的详细信息。 有关可能返回的错误的详细信息,请参阅 COM 库参考中的 HRESULT 值。

对象比较

对于 Tablet PC 平台托管库中的所有对象,不会重写 Equals 来正确比较两个相同的对象。 托管应用程序编程接口 (API) 不支持通过 Equals 函数或通过 equals (==) 运算符比较对象是否相等。

绑定到最新Microsoft.Ink.dll

最新的 Microsoft.Ink.dll 程序集是Microsoft.Ink.dll版本 1.0 和 Microsoft.Ink.15.dll 的兼容替代项。 在大多数情况下,无需对随旧程序集一起分发的应用程序进行任何更改。 但是,在某些情况下,你需要指示公共语言运行时加载程序使用较新的动态链接库 (DLL) ,无论引用了较旧的 DLL。

仅当应用程序将引用版本 1.0 或 1.5 程序集的组件与引用较新版本程序集(如 1.7)的组件结合使用时,以及这些组件是否可以交换数据,则唯一需要使用以下技术显式绑定到新程序集的情况。

指示公共语言运行时加载程序使用较新 DLL 的最佳方法是在应用程序级别重定向程序集版本。 可以通过将程序集绑定信息放入应用程序的配置文件来指定应用程序使用较新版本的程序集。 有关在应用程序级别重定向程序集版本的详细信息,请参阅 重定向程序集版本,特别是“在配置文件中指定程序集绑定”部分。

需要在可执行文件所在的同一目录中创建配置文件。 配置文件必须与可执行文件同名,后跟.config文件扩展名。 例如,对于应用程序,MyApp.exe,配置文件必须是MyApp.exe.config文件。 配置文件使用 bindingRedirect 元素强制将所有以前的版本映射到最新版本,如以下示例所示:

<bindingRedirect oldVersion="0.0.0.0-1.7.2600.xxxx" newVersion="1.7.2600.xxxx" />

有关配置文件的详细信息,包括如何为配置文件构造 Extensible Markup Language (XML) 的示例,请参阅 bindingRedirectRedirecting Assembly Versions

使用 Microsoft Windows XP Tablet PC Edition Development Kit 1.7 及更高版本创建的应用程序会自动绑定到新版本的 Microsoft.Ink 程序集。 有关程序集绑定的详细信息 ,请参阅运行时如何定位程序集

注意

使用应用程序策略绑定到更新的程序集不适用于使用 Divider 类或 PenInputPanel 类的应用程序。 使用上述任一类的应用程序必须继续使用 Microsoft.Ink.15.dll或在引用更新的程序集后重新编译。

 

使用事件

如果任何托管对象的事件处理程序中的代码引发异常,则不会将异常传递给用户。 若要确保传递异常,请在托管事件的事件处理程序中使用 try-catch 块。

管理窗体

Form 类及其基类不定义终结器。 若要清理窗体上的资源,请编写一个子类,该子类提供终结器 (例如,使用调用 Dispose 的 ~) C# 析构函数。 若要执行清理,终结器将替代 Dispose,然后调用基类 Dispose。 当布尔参数为 FALSE 时,请勿引用 Dispose 方法中需要 Finalize 方法的其他对象,因为这些对象可能已经完成。 有关释放资源的详细信息,请参阅 Finalize 方法和析构函数

Forms 和 RecognizerContext

RecognizerContext 事件在与窗体位于的线程不同的线程中运行。 Windows 窗体 中的控件绑定到特定线程,并且不是线程安全的。 因此,必须使用控件的调用方法之一来封送对正确线程的调用。 控件上的四种方法是线程安全的: InvokeBeginInvokeEndInvokeCreateGraphics 方法。 对于所有其他方法调用,在从其他线程调用时,请使用其中一个调用方法。 有关使用这些方法的详细信息,请参阅 从线程操作控件

正在等待事件

平板电脑环境是多线程的。 使用 CoWaitForMultipleHandles 函数(而不是其他等待方法)允许重新进入组件对象模型 (COM) 调用,以便在应用程序等待事件时进入多线程单元 (MTA) 。

使用墨迹笔划集合

Ink 对象获取的 Strokes 集合实例不会进行垃圾回收。 为了避免内存泄漏,每当使用其中一个集合时,请使用“using”语句,如下所示。

using (Strokes strokes = myInk.Strokes)
{
    int i = strokes.Count;
}

释放托管对象和控件

若要避免内存泄漏,必须在对象或控件超出范围之前,对已附加事件处理程序的任何 Tablet PC 对象或控件显式调用 Dispose 方法。

若要提高应用程序的性能,请在不再需要以下对象、控件和集合时手动释放它们。

以下 C# 示例演示了使用 Dispose 方法的一些方案。

// A field for a Divider object
private Microsoft.Ink.Divider theDivider;

// A method that creates a Divider object
public void CreateDivider()
{
    // Make sure any previous Divider object was disposed of.
    if (null != theDivider)
    {
        theDivider.Dispose();
        theDivider = null;
    }
    // Create the Divider object.
    theDivider = new Microsoft.Ink.Divider();

    // The remainder of the method
}

// A method that disposes of the Divider object
public void DisposeDivider()
{
    // The remainder of the method

    // Dispose of the Divider object.
    if (null != theDivider)
    {
        theDivider.Dispose();
        theDivider = null;
    }
}

// A method that uses a local PenInputPanel object.
public void UsePenInputPanel()
{
    // Create the PenInputPanel object.
    Microsoft.Ink.PenInputPanel thePenInputPanel =
        new Microsoft.Ink.PenInputPanel();

    // The remainder of the method

    // Dispose of the PenInputPanel object before exiting.
    thePenInputPanel.Dispose();
    thePenInputPanel = null;
}