分享
 
 
 

Mobile Ink Jots 3:在 Web 上写写画画

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

Mobile Ink Jots 3:在 Web 上写写画画

发布日期: 10/13/2004 | 更新日期: 10/13/2004

Shawn A. Van Ness

Leszynski Group

适用于:

Microsoft ® Windows® XP Tablet PC Edition 2005

摘要:即将发布的 Tablet PC 平台和 SDK(代号为“Lonestar”)提供了人们期待已久的对启用手写的 Web 应用程序的支持。本月,Shawn 告诉我们那意味着什么,并向我们展示了它是如何做到的。

本页内容

简介

什么是 Web 应用程序?

在 Internet Explorer 中宿主启用手写的控件

回发到 Web 服务器

俭则不匮

通过 HTTP 部署富客户端 Tablet PC 应用程序

支持非 Tablet 客户端的选项

小结

简介

欢迎回到 Mobile Ink Jots。现在是七月份,发布 Windows XP Service Pack 2 (SP2) 已进入倒计时了。如果您读过我以前的专栏,或以任何方式一直跟着最新 Tablet PC 开发的脚步,毫无疑问您已经知道 Windows XP SP2 将包括 Tablet PC 的“Lonestar”版 — 一个正式名称为 Windows XP Tablet PC 2005 版的版本。

上个月,我们漫游了 Lonestar,从一个开发人员的角度介绍了新功能。我们涵盖的主题范围非常广泛(从对手写识别体验的增强,到新的 RealTimeStylus API),但只是进行概述。从本月开始,我们将更详细地介绍其中的每个主题。

对于 Lonestar 备有的所有新功能,最为开发人员所热切期望的是新添加的对在 Web 上手写的支持。那么,让我们开始深入研究一下它带来了什么好处,以及在各种基于 Web 的应用程序方案中运行手写应用程序实际意味着什么。

返回页首

什么是 Web 应用程序?

它对支持手写的应用程序来说意味着什么?这些是有关存在的问题,但就技术而言,即便是在 2004 年,Web 仍然是一个非常混乱的概念区域。谈到这类内容时,我们必须非常谨慎而且非常明确。对不同的人来说,“Web 应用程序”这一短语意味着截然不同的东西。

对于初学者来说,我们不是在讨论 ASP.NET 对比 PHP 对比 JavaServer Pages (JSP) 或您有的东西。这是因为根本没有这个必要 — 所有这些服务器端 Web 技术都能用于为 Tablet PC 客户端提供丰富的、支持手写的内容(稍后会介绍更多有关此方面的内容)。更确切地说,我们需要关心的 Web 技术几乎全部是客户端层:如何提供优于 Web 浏览器内置功能的丰富用户体验,从而允许手写的收集和呈现。例如,如何加载(和编写)一个嵌入在 Web 页中的启用手写的控件?

当然,目前 Web 不再与浏览器密切结合。成熟的富客户端应用程序与 Web 服务通讯,而其中从没有显示任何 HTML,这种情况也并非罕见。但是,这类启用 Web 的客户端应用程序对“Web 应用程序”来说并不是一个非常有用的定义。很多 Tablet PC 应用程序都是按这种方式设计的。为了本次讨论,我会将 Web 应用程序定义为任何程序或组件代码 — 其自身通过 HTTP 部署,从而使对访问 Web 服务器的客户端变得无缝可用,而无须安装、配置或维护任何东西。

在过去十年的大部分时间中,Java 小程序和 Microsoft ActiveX_ 组件构成了富客户端层 Web 应用程序技术的基础。但是对于 .NET Framework 来说,ActiveX 控件是一项被极力反对的技术(而且在 Tablet PC 的开发期间,使用 Java 是无法成功的)。没关系。.NET Framework 给双方提供了一个更好的选择:我们可以使用 C# 或 Microsoft Visual Basic_ .NET 以及 .NET Framework 的 Windows Forms 类在我们的 Web 应用程序中实现富客户端层功能。这是真的,无论我们需要在 Internet Explorer Web 页中添加一个自定义控件,还是开发一个带有其自己的框架窗口的独立可执行文件(或者可能是二者的某种结合)都是如此。相同的 .NET Framework 技术 — Windows Forms、代码访问安全性,以及现在的 Microsoft.Ink,应用于所有这两个解决方案。

从 1.0 版本开始,.NET Framework 已经支持通过 HTTP 进行代码的部署和分发。Windows Forms 可执行文件可以很简单地部署在 Web 服务器上,并在 URL 上运行 — 一种称为无接触部署的方法 — Internet Explorer 5.01 版引入了 object 标记的一种新语法,它允许加载托管 Windows Forms 控件而不是 ActiveX 控件。不过,支持在这些“移动代码”方案中运行手写对 Tablet PC 的 Lonestar 版来说是个新功能。

在上述任一情况下,只要 .NET Framework 运行库执行移动代码(任何从远程源— 通常是 Web 服务器,但也可能是 FTP 站点或映射网络驱动器 — 获得的代码),该代码就会受名为沙箱(听起来有点古怪)的东西的约束。Java 是沙箱安全模型的先驱,使得全世界的用户可以安全地在任意 Web 站点上与 Java 小程序进行交互,而无须过多地担心这些小程序会将硬盘重新格式化,或窃取我们的个人信息,或有其他不轨行为。

通过自动映射一组基于证据 的权限,.NET Framework 在 Java 沙箱安全模式上进行了改进,该证据有效地具有关于代码来自何处和/或由谁编写的可信信息。这意味着,在默认情况下,与从本地 Intranet 下载的控件和程序相比,从 Internet 下载的程序和控件普遍以一个更受限制的权限集(将其看作一个更小的沙箱)运行。从一个逻辑极端来讲,从计算机的本地硬盘运行的代码得到整个权限集(或者根本没有沙箱,或者有一个无穷大的沙箱,这取决于您的观点)。从另一个逻辑极端来讲,从一个在 Internet Explorer 的受限站点区域中列出的站点运行的代码根本得不到任何权限去运行。

随着讨论的进行,我们将对代码访问安全做更详细的探讨。首先,让我们开始学习如何在 Internet Explorer(毫无疑问它还宿主大多数瘦客户端 Web 应用程序)中宿主启用手写的自定义控件。

返回页首

在 Internet Explorer 中宿主启用手写的控件

在 MSDN Magazine 的 2002 年一月刊中,Jay Allen 的文章 Host Secure, Lightweight Client-Side Controls in Microsoft Internet Explorer 提供了一个关于在 Internet Explorer 中宿主托管 Windows Forms 控件的非常好的背景。本文中的示例使用了一个 ActiveX-era <object> 标记的重载。对于那些缺乏经验的人来说,这里有一个必要的 HTML 代码的简单示例,如下所示:

<object classid="MyControls.dll#MyControls.UserControl1"

width="300" height="200" id="uc1">

<param name="BackColor" value="#808080" />

<param name="Text" value="You get the idea..." />

Sorry, your browser doesn't seem to support .NET controls.

</object>

与宿主 ActiveX 控件相比,关于这个新的 HTML 语法,的确有一些重要的事情需要注意。正如您会看到的,classid 属性已经被重载,以指定该控件的程序集的位置,以及它的与一个“#”字符连接在一起的完整托管类型名称。该程序集的位置被指定为一个 URL,相对于该页的基 URL,就像任何普通的超级链接,或者到外部图像、样式表或脚本文件的链接。

官方说法是,为了在使用这一新语法时加载托管控件,需要 Internet Explorer 5.01 版或更高版本;但我建议使用更高版本。Internet Explorer 5.5 和 6.0 版在这一方面提供了若干种极其有效的修补程序,其中有一些特别针对于与 Microsoft.Ink 命名空间组件的交互。

关于这个新的object标记语法,有一件重要的事情需要注意:直接从全局程序集缓存加载托管控件是不可能的。该控件的程序集必须通过指定的 URL 访问。例如,将一个 Windows Forms PictureBox 控件直接加载到 Web 页中是不可能的:

<!-- THIS DOESN'T WORK -->

<object

classid="System.Windows.Forms.dll#System.Windows.Forms.PictureBox"

width="300" height="200" id="pb1">

</object>

不过,从 Windows Forms 的 PictureBox 类派生您自己的控件,并将此控件宿主到 Web 浏览器中是完全可能的。System.Windows.Forms.dll 上的程序集依赖项将通过 .NET Framework£¨它当然包括全局程序集缓存)的默认探测路径解析。

那么,手写支持的情况又怎样呢?由于相同的原因,我们不能直接加载 Windows Forms PictureBox 的实例,我们不能从驻留在客户端的全局程序集缓存中的 Microsoft.Ink 程序集直接将一个 InkPictureInkEdit 控件实例化。我们必须派生自己的控件,这样做很好,因为实际上,无论如何我们都不希望将自己限于 InkPicture 和 InkEdit。通常,我们当然希望编写自己的用户界面控件,附加 InkCollectorInkOverlay 对象,并完全按照我们希望的方式在我们希望的地方执行识别。

下列的示例代码演示了一个简单但完整的、由 UserControl 派生的 Windows Forms 类,它带有一个附加的 InkCollector 对象。

namespace MyControls

{

public class InkableUserControl : System.Windows.Forms.UserControl

{

private Microsoft.Ink.InkCollector inkCollector;

public InkableUserControl()

{

// This call is required by the Windows.Forms Form Designer.

InitializeComponent();

// Further initialization

this.BackColor = Color.FromKnownColor(KnownColor.Window);

this.inkCollector = new InkCollector(this); // secure!

this.inkCollector.Enabled = true;

}

}

}

对 Lonestar 来说,有什么新内容呢?您可能注意到的第一件事(尤其是如果您没有安装 Tablet PC 平台 SDK 1.7 版的话)是 InkCollector 对象的新构造函数重载,这将带来一个对托管 Windows Forms 控件实例而非原始 Win32 窗口句柄的引用。精细,是吗?(没有 Lonestar SDK,上面的代码产生一个更不精细的编译器错误。)InkCollector 要与 Windows Forms 对象在一个安全的、严格受约束的、适用于 Internet 应用程序的沙箱中进行交互,则需要这个新的构造函数重载。

如果您使用旧式构造函数(例如,用前面代码中的 new InkCollector(this.Handle) 替换 new InkCollector(this)),控件将要求权限来接触系统上的全部窗口以及执行非托管代码。这是一个极大的沙箱,它实际上根本不适用于运行移动代码。事实上,在默认情况下,试图调用一个旧式构造函数在 Intranet 和 Internet 区域中都会引发 SecurityException

第二个新内容(从上面的代码中看不到)是,Microsoft.Ink 程序集的 1.7 版现在带有 AllowPartiallyTrustedCallersAttribute。这个名称极长、极为重要的小属性(有时简称为 APTCA)就如同一个安全开关。此属性是一个选择性加入 (opt-in) 标志,用于声明一个程序集完成了安全检查的某种衡量,并被认为在部分受信任的上下文中安全可用。这意味着,应用程序在一个沙箱中使用此程序集是安全的。如果您的程序集是具有强名称的,则为了从 Web 页使用此属性,也会需要将其添加到您自己的代码中(当然,是在对任何潜在安全问题给予应有的考虑之后)。

注 Lonestar SDK 文档中的安全和信任主题描述需要特定权限的 Tablet PC SDK 的多种 API 元素。事实上,在 Web 上使用手写的整个部分都是新的,而且 SDK 中的示例现在包括 AutoClaims 示例的一个支持 Web 的版本,甚至包括一个支持手写的网络日记引擎的开头。

返回页首

回发到 Web 服务器

几个新构造函数和一个新属性 — 这就是全部内容吗?不尽然。除非您的应用程序的唯一要求是为了让 Tablet PC 用户能够在浏览您的 Web 站点的时候草记自己的短小备忘,否则收集手写也就不显得那么重要了。您可能想用手写真正地做一些事,比如将其回发到 Web 服务或数据库。

这里有两个选项。第一个选项是撰写脚本:通过使用客户端<script>,我们几乎可以调用托管控件上的任何公共属性或方法。返回值可用于填充回发中的隐藏字段,或执行任何其他您可以想象到的 DHTML 技巧。

此 HTML 代码是我们已经看到的片段的展开。我们控件的 <object> 标记现在包含在一个更大的 <form> 元素中,在一些其他的控件旁边,而且我们已经编写了数行脚本来将它们与某个丰富行为绑定在一起:单击超级链接调用我们控件上的 Recognize() 方法,并用结果填充该窗体的文本框。

<form action="/inktest/backend.asmx" method="post">

<p>Please sign in the box, below:</p>

<object id="ink1" classid="MyControls.dll#MyControls.InkableUserControl">

<param name="BackColor" value="#E0E090">

</object>

<a HREF="#" TARGET="_self" onclick="setRecoText()">Recognized text:</a>

<input type="text" name="text1" size="20" />

<input type="submit" name="submit" value="Submit!" />

</form>

<script language="jscript">

function setRecoText() {

var recotext = document.forms[0].ink1.Recognize();

document.forms[0].text1.value = recotext;

}

</script>

此 HTML 代码是我们已经看到的片段的展开。我们控件的 <object> 标记现在包含在一个更大的 <form> 元素中,在一些其他的控件旁边,而且我们已经编写了数行脚本来将它们与某个丰富行为绑定在一起:单击超级链接调用我们控件上的Recognize()方法,并用结果填充该窗体的文本框。

namespace MyControls

{

public class InkableUserControl : System.Windows.Forms.UserControl

{

private Microsoft.Ink.InkCollector inkCollector;

public InkableUserControl()

{

this.BackColor = Color.FromKnownColor(KnownColor.Window);

this.Size = new System.Drawing.Size(300, 200);

this.inkCollector = new InkCollector(this);

this.inkCollector.Enabled = true;

}

// We invoke this method explicitly, through script,

// to recognize the user's writing.

public string Recognize()

{

return this.inkCollector.Ink.Strokes.ToString();

}

// This property is invoked by Reflection,

// when Internet Explorer posts our UserControl

// as part of a <form> block.

public string Value

{

get

{ return GetBase64Ink(); }

}

// Serialize the Ink as Base64 ISF, max compression.

private string GetBase64Ink()

{

byte[] inkbits = this.inkCollector.Ink.Save(

PersistenceFormat.Base64InkSerializedFormat,CompressionMode.Maximum);

return Convert.ToBase64String(inkbits);

}

}

}

此 C# 代码也与我们已经看到的 Windows Forms 控件代码相似。仅有的新功能是脚本可调用的 Recognize() 方法,以及在表单发送期间可由 Internet Explorer 隐式调用的 Value 属性。

我们完成了吗?基本上是。还有一个任务,是我们绝对不应忽视的:资源管理。

返回页首

俭则不匮

Tablet PC SDK 的 1.5 版将 IDisposable 实现添加到许多核心 Ink 类中,特别是 InkCollector 和 InkOverlay。虽然 .NET Framework 类库中的许多 API 允许忽略 IDisposable 而不会产生太大问题(其完成器方法被设计为执行完全相同的清理),但 Microsoft.Ink 中的类不能这样做。对此有一个完美的解释,但我不知道,否则会与您分享。要满足完全解构 InkCollector 或 InkOverlay 的实例的需要,有两件事是必须做的:我们必须 调用 IDisposable.Dispose,并且 等待垃圾回收器运行。

部署任何 Tablet PC 应用程序时,请紧记这个建议。它适用于 Windows Forms 应用程序和 Web 应用程序。但是在后一种情况中,从何处且如何调用 Dispose() 呢?我们需要在 HTML 中多编写几行脚本,以在页面卸载时显式销毁 Ink 控件:

<body onunload="onUnload()">

...

<script language="jscript">

function onUnload() {

// Must explicitly dispose Ink resources!

document.forms[0].ink1.Dispose();

}

</script>

当然,回到我们的 C# 代码中,必须确保将我们控件的 Dispose() 重写恰当地转发到 InkCollector:

protected override void Dispose(bool @explicit)

{

if (@explicit)

{

// Fwd to IDisposable members.

this.inkCollector.Dispose();

this.inkCollector = null;

}

base.Dispose(@explicit);

}

这就是与此相关的全部内容。

返回页首

通过 HTTP 部署富客户端 Tablet PC 应用程序

长期以来,Internet Explorer 是瘦客户端 Web 应用程序的支柱,但任何在远离家和办公室的时候查看电子邮件的人都知道,基于浏览器的界面有其限制。它们根本不利用像 Microsoft Outlook_ 这样的富客户端的可用性和强大功能。

面对现实吧,开发基于浏览器的应用程序是困难的。调试客户端脚本会是非常令人沮丧的,很多项目的很大一部分开发预算都不当地花在了与 CSS 的古怪问题作斗争上,或设计独特而卑鄙的方法来阻止用户单击“返回”按钮上。这对任何人的 Web 体验都没有增值。当然,我们的老板和客户都宁愿将时间用在修复真正的错误以及给我们的应用程序添加真正的功能上。

终于,在一个通过 HTTP 部署的功能齐全、丰富的 Windows Forms 中,.NET Framework 为我们提供了一个更好的选择。如我前面所提到的,这一技术被称为无接触部署。MSDN Magazine 的 2002 年七月刊中有 Chris Sells 的关于无接触部署的开创性文章 Security and Versioning Models in the Windows Forms Engine Help You Create and Deploy Smart Clients,继这篇文章之后也出现了很多其他的好文章,包括 Launching No-Touch Deployment Applications with Command Line ArgumentsDeploying and Updating Smart Client Applications。另外,在即将发布的 Windows 版本和 .NET Framework 中,无接触部署会得到改进,并有一个新名字,叫做 ClickOnce — 从而获得更好的、更灵活的部署选项,包括对脱机操作的支持。

关于无接触部署没有太多要说的。入门很简单:只需开发一个 Windows Forms 可执行文件,并将其发布在您的 Web 服务器上。当用户跟随一个超级链接到该 .exe 文件时,Internet Explorer 将下载并启动该应用程序,并在嵌入在 Web 页中的控件的同一个安全沙箱(前面提到过它)中运行它。.NET Framework 运行库甚至在应用程序的框架窗口上显示一个气球提示,告诉用户程序是以受限制的功能运行的。

棘手的事总是在细节中。配置 Web 服务器以给出 .config 文件和其他依赖项有时可能是棘手的,而且 .NET Framework 的版本语义和 HTTP 的 If-Modified-Since 标头语义的交集有时可能是极其令人困惑的。Chris Sell 的文章可以很好地帮助您处理这些麻烦事。在 ClickOnce 发布之前,我要强调的一点是,您在实际尝试任何无接触部署前,必须要阅读 Chris 的文章。

在任何情况下,我们必须切记,从 Internet 区域运行的应用程序的默认代码访问安全策略是相当严格的:在尝试设计一个丰富的全功能 Windows Forms 应用程序时,经常会遇到代码访问安全的问题。这里有一个预期您可能遇到的 .NET Framework 1.1 版(1.0 版根本不允许从 Internet 区域执行)的一些限制的部分列表:

没有非托管代码或本地窗口处理。

不能反射,不能序列化。

没有磁盘 I/O(除 IsolatedStorageOpenFileDialog 之外)。

没有网络 I/O (除了连接回起始服务器的功能之外)。

不能与其他应用程序进行剪贴板互操作。

有限的 ADO.NET 访问权。

不能进行 XSL 转换。

默认情况下,由 Intranet 区域内提供的应用程序的沙箱只稍微大一点:

文件打开和文件保存对话框的不受限制使用。

不受限制的用户界面功能(但不包括本地窗口处理)访问权。

添加的用于进行 DNS 查询、记住当前用户名、发送到 EventLog、从本地目录读取等功能 — 所有有问题的用途。

不要弄错了,这些相同的默认代码访问安全策略应用于寄宿在 Internet Explorer Web 页中的控件。那只是因为,与开发一个简单的控件来收集 Web 页上的手写输入相比,在开发一个全功能的富应用程序时,它们有时看起来可能过度约束。

另一方面,对于寄宿在一个 Web 页面中的控件来说,代码访问的安全性通常是一个更大的问题。页面的脚本代码从托管控件接收事件是不太可能的,除非起始 Web 站点被授予高级别的信任。而且,Windows XP Service Pack 2 可能完全禁用脚本从托管代码接收事件的功能。(接收带有非托管脚本的托管事件相当于调入 COM 代码的托管代码,这意味着执行非托管代码的功能 — 不用担心非托管脚本很可能已经在浏览器中一直执行这一事实!)

那么,如果您仔细考虑了应用程序将在其中运行的代码访问安全上下文,并能够容忍代码访问安全设置的限制,则与使用 Web 页面相比,使用无接触部署的智能客户端会为 Tablet PC 用户提供更高质量的体验。简单地说,对于新应用程序部署来说,HTML 不是一个好平台。即便是最佳的基于 Web 的电子邮件界面也不例外。

返回页首

支持非 Tablet 客户端的选项

不管您是在保持一个旧式的、基于浏览器的 Web 应用程序,还是在开发一个新的最先进的智能客户端,您可能都会发现自己既需要支持 Tablet PC,又需要支持下级(非 Tablet PC)客户端平台。

对于基于浏览器的应用程序,这通常意味着省略来自 HTML 流的 @@@object### 标记(可能提供一些可选的 UI 因素,或一个完全不同的页面布局)。在没有 Microsoft.Ink 时,智能客户端应用程序有可以完全降低其功能的众多选项。最明显的是 — 尽管可能不太精致 — 为 Tablet PC 和下级客户端以及重定向客户端相应地生成并部署二进制文件。

在任一情况下,都需要同一技巧:为了提供最恰当的内容(HTML 或可执行的托管代码),Web 服务器需要知道客户端是否正在运行 Windows XP Tablet PC 2005 版。

如我上个月提到的,Windows XP Tablet PC 2005 版上的 Internet Explorer 将挤出几个额外的比特到 User-Agent 字符串中,允许 Web 服务器只做这些:

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;

.NET CLR 1.0.3705; .NET CLR 1.1.4322; Tablet PC 1.7)

Web 服务器将以前版本的 Tablet PC 客户端与普通的 Windows XP 客户端区分开来,并以不同的内容响应,这曾经是(而且目前仍然是)近乎不可能的。从技术上讲,这不是问题,这是因为在 Lonestar 之前,根本不正式支持在移动代码应用程序中宿主手写。

用于在 User-Agent HTTP 头中检测 Tablet PC 签名的 ASP.NET 代码很简单。但是在响应时做什么是取决于您的。(您发出了不同的页面内容吗?重定向到一个不同的子站点?生成并提交一个新 Tablet PC 的采购定单?您明白了。)

if (Request.UserAgent.IndexOf("Tablet PC 1.7") > -1)

{

// The client browser is a Lonestar-upgraded Tablet PC.

ServeInkEnabledContent();

}

else

{

// The browser is either not a Tablet PC, or a pre-Lonestar Tablet PC

// (neither of which support hosting Ink).

ServeDownLevelContent();

}

如果您不想编写自定义后端代码,或者不想针对两个不同客户端平台维护并测试您 Web 应用程序的两个不同“视图”,那会怎么样呢?我理解您。有一个更棒的解决方案,尽管它有点黑客化:在没有 Ink 运行时库的时候,将任何 Microsoft.Ink 类型的实例和使用封装在一个 try/catch 块中是可能的,这样可以在下级平台上完全降低我们的控件的功能。这里有一个例子,是关于如何能够完全降低我们上面看到的 C# InkableUserControl,来作为一个下级系统上的多行 TextBox 控件:

public class InkableUserControl : System.Windows.Forms.UserControl

{

private object inkCollector; // weakly typed!

public InkableUserControl()

{

this.BackColor = Color.FromKnownColor(KnownColor.Window);

this.Size = new System.Drawing.Size(300, 200);

// Guard against absence of Tablet PC runtime with messy downcasting

// and exception-handling around JIT compilation.

try

{

// Note: Because JIT compilation happens on a method-by-method

// basis, we must factor out any calls to Ink into a subroutine,

// in order to catch the exception thrown from Fusion, here.

AttemptInitializeInk();

}

catch (System.IO.FileNotFoundException) // missing Microsoft.Ink.dll!

{

// We couldn't find Microsoft.Ink (not the version we wanted,

// anyway) so let's degrade down to multiline TextBox.

TextBox downlevelTextBox = new TextBox();

downlevelTextBox.Multiline = true;

downlevelTextBox.Dock = DockStyle.Fill;

downlevelTextBox.Text = "What? No Tablet PC?";

this.Controls.Add(downlevelTextBox);

}

}

private void AttemptInitializeInk()

{

inkCollector = new InkCollector(this.Handle);

((InkCollector)inkCollector).Enabled = true;

}

protected override void Dispose(bool @explicit)

{

if (@explicit)

{

// Fwd to IDisposable members.

((IDisposable)this.inkCollector).Dispose();

this.inkCollector = null;

}

base.Dispose(@explicit);

}

...

}

请注意,除了 JIT 编译周围的粗糙的异常处理外,还需要麻烦的向下转换(InkCollector 成员被一个弱类型化的 System.Object 引用替换),从而避免对 Microsoft.Ink 的依赖太强。这是一种非常难看的、非常容易出错的代码样式。我真的不建议使用它。因为它令人难以置信地低效,我甚至对公开演示它感到犹豫。对 Microsoft.Ink 方法的每个潜在调用,将导致 .NET Framework 程序集加载器对 Web 服务器发出若干请求,探测 Microsoft.Ink.dll 是否在通常的位置,在最终放弃并引发异常之前,这本身可能是一个代价高昂的操作。但我也认识到,在对多客户端平台的支持中生成并部署一组二进制文件,有时真的是非常方便的。好消息是我们有选择。

返回页首

小结

Tablet PC 是一个强大的、创新的平台,而且在构建富应用程序以利用其独特的功能方面,Microsoft 已经为我们提供了大量的工具和组件。不过,想知道如何能使这个新平台的功能与瘦客户端 Web 应用程序(软件技术的上一项伟大创新)很好地合作,是很自然的。

终于,Tablet PC 平台的 Lonestar 版将对手写的支持添加在了瘦客户端、移动代码应用程序方案中,无论那对您意味着什么 — 宿主在 Internet Explorer 中的基于 HTML 的 Web 应用程序,或部署在 HTTP 上的全功能 Windows Forms 应用程序。对于新开发,无接触部署是最好的方法,但手写功能可以相当容易地更新到旧式的基于浏览器的应用程序中。

一旦 Lonestar 作为 Windows XP Service Pack 2 的一部分发布,通过利用基于笔的 UI 和 Tablet PC 的微小格式因素,数百(或许数千)基于 Web 的应用程序将得到巨大的改进,这肯定没错。寻找使其发生的方法是本月专栏的主题。还有一个迫在眉睫的问题:谁将第一个使其网络日记启用手写?

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有