XForms技术在C#应用程序中的应用

XForms是由W3C推荐的一种重要技术,它允许以简单、声明式的语法定义复杂的XML处理应用程序。本文将展示如何在C#应用程序中利用这项技术。这些技术同样可以轻松地应用于其他.NET语言,或者任何具有COM绑定的编程语言。XForms的核心渲染能力由Ubiquity formsPlayer提供,这是一个免费的开源XForms处理器。

为什么选择XForms?

XForms相对于其他解决方案的优势在其他地方已经得到了更详细的讨论,这里不再赘述。有兴趣深入了解的读者可以参考文章末尾的链接。简而言之,XForms的一些关键优势包括:

  • XForms文档是设备和平台独立的。
  • XForms使用声明式语法,有助于加快开发速度,并减少与传统的、过程化方法相比的潜在错误。
  • XForms根据模型-视图-控制器(MVC)设计模式分离数据、用户界面和应用程序逻辑。
  • XForms是一个开放标准,这意味着相同的文档可以在所有符合标准的处理器上部署,无需修改。
  • XForms文档在设计上是可访问的。
  • XForms在输入点启用全面的输入验证,减少了分布式Web应用程序中服务器往返的需求。

开始之前

在开始之前,需要安装Ubiquity formsPlayer,这是一个免费且相对较小的下载。此外,还需要单独安装Ubiquity Browser eXtensions以获取可嵌入的Renderer组件。安装这两个组件后,必须通过'添加引用'对话框将两个COM库导入C#项目:

  • [Program Files]\Common Files\UBX\Renderer\Renderer5.dll
  • [Program Files]\Common Files\UBX\DOM\DOM2Events.dll

这两个库中的第一个,Renderer,为所有的XHTML和XForms渲染功能提供了一个包装器。第二个组件,W3C的DOM Level 2 Events建议的实现,促进了应用程序、Renderer和活动文档之间的通信。

实例化Renderer

首先,必须在应用程序中添加一个新的类,代表将托管Renderer的窗口。在示例代码中,这个类被称为RenHost。这个类的构造函数需要实例化一个RenderLib.RendererClass的副本,并存储一个指向实例的IRender接口的指针:

public class RenHost : Form { private RenderLib.IRender renderer; ... public RenHost() { InitializeComponent(); this.components = new System.ComponentModel.Container(); this.components.Add(this.buttonOpen); this.components.Add(this.labelUrl); this.components.Add(this.textboxUrl); this.components.Add(this.panelRenderer); this.createRenderer(); } private void createRenderer() { this.renderer = (RenderLib.IRender) new RenderLib.RendererClass(); } ... }

接下来,必须使this.renderer成为RenHost类上的Panel的子元素。这是通过调用Initialise()并传递Panel的句柄作为参数来实现的:

private void createRenderer() { this.renderer = (RenderLib.IRender) new RenderLib.RendererClass(); this.renderer.Initialise(null, (int)this.panelRenderer.Handle); }

分派事件

现在,应用程序可以自定义this.renderer的各种特性,例如设置其初始大小或指示它将任何导航请求委托给应用程序。这些属性和其他许多属性都是通过分派事件到this.renderer的IEventTarget接口来设置的。

private void dispatchEvent(String type, int arg1, int arg2, String arg3) { DOM2EventsLib.IRendererEvent rendererEvent = (DOM2EventsLib.IRendererEvent) new DOM2EventsLib.RendererEvent(); rendererEvent.initRendererEvent(type, false, false, arg1, arg2, arg3); DOM2EventsLib.IEventTarget eventTarget = (DOM2EventsLib.IEventTarget) this.renderer; eventTarget.dispatchEvent((DOM2EventsLib.DOMEvent)rendererEvent); }

目前不必担心所有不同的参数意味着什么。只需知道上面的代码允许分派一个指定类型的renderer事件,以及一些事件特定的上下文参数。

初始化Renderer实例

首先,需要使用新方法通知this.renderer其初始大小和位置:

private void createRenderer() { this.renderer = (RenderLib.IRender) new RenderLib.RendererClass(); this.renderer.Initialise(null, (int)this.panelRenderer.Handle); this.dispatchEvent("renderer-set-dimensions", this.panelRenderer.ClientRectangle.Width, this.panelRenderer.ClientRectangle.Height, ""); this.dispatchEvent("renderer-set-position", 0, 0, ""); }

还需要确保this.renderer得到通知父窗口发生的任何调整大小。这需要为Resize事件添加一个处理程序:

private void panelRenderer_Resize(object sender, EventArgs evt) { this.dispatchEvent("renderer-set-dimensions", this.panelRenderer.ClientRectangle.Width, this.panelRenderer.ClientRectangle.Height, ""); }

一旦这些初始窗口相关的属性被设置,必须指示this.renderer积极拥有其Panel:

private void createRenderer() { this.renderer = (RenderLib.IRender) new RenderLib.RendererClass(); this.renderer.Initialise(null, (int)this.panelRenderer.Handle); this.dispatchEvent("renderer-set-dimensions", this.panelRenderer.ClientRectangle.Width, this.panelRenderer.ClientRectangle.Height, ""); this.dispatchEvent("renderer-set-position", 0, 0, ""); this.dispatchEvent("renderer-activate", 0, 0, ""); }

渲染文档

renderer实例现在已经初始化并准备好显示文档。这本身就是一个两阶段的过程。首先,文档必须以两种方式之一加载:

  • 通过将标记的字符串表示传递给LoadFromString()。
  • 通过传递Microsoft IXMLDOMDocument接口指针给LoadFromDOM()。
private void loadDocument() { XmlDocument document = new XmlDocument(); Uri uri = this.getUri(); try { document.Load(uri.AbsoluteUri); this.renderer.LoadFromString(document.OuterXml, this.getBase(uri)); this.renderer.Render(this.getFragmentId()); } catch (XmlException exception) { MessageBox.Show(this, "Failed to parse " + exception.SourceUri + "\n\nReason: " + exception.Message + "\nLine: " + exception.LineNumber + "\nColumn: " + exception.LinePosition + "\nSource: " + exception.Source, "RenHost XML parse error"); } catch (COMException exception) { MessageBox.Show(this, "The renderer component encountered an error\n" + exception.StackTrace, "RenHost error"); } }

清理

protected override void Dispose(bool disposing) { this.destroyRenderer(); if (disposing && this.components != null) { this.components.Dispose(); } base.Dispose(disposing); } private void destroyRenderer() { this.renderer.Destroy(); this.renderer = null; }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485