WPF,即 Windows Presentation Foundation,是一套开发 Windows 应用程序的.NET API。已经有太多资料谈到 WPF 的出现让开发视觉效果非凡的应用程序变得前所未有的容易,不过其实 WPF 也是一种开发前端应用程序的强大技术,尽管这一点似乎关注的人不多。尤其在.NET 框架对可连接系统(Connected Systems)强有力的支持下,通过结合 WPF 中的数据绑定能力,使 WPF 成为了一种富有竞争力表现技术,为使用 Java、Ruby 或.NET 等任何技术开发的后台进行前台呈现。
在这篇文章中,我们会把 WPF 和其他一些技术,例如 AJAX/DHTML、Swing 或 Flash 进行对比;然后我们会分享一些使用 WPF 作为客户端的合适场景,这些示例会使用 Java 作为后台开发技术。
WPF 是一个用于开发富客户端应用程序的平台。它是.NET 3.0 框架的一部分,因此已经在 Windows Vista 中内置,此外它也能够在 Windows XP SP 2 以及 Windows 2003 中安装。构建 WPF 用户界面可以使用.NET 对象模型,不过 WPF 也提供 XAML——即 eXtensible Application Markup Language——这是一种标记语言,使用户界面的表现能够独立于其行为进行设计。两种做法实际上是等价的,XAML 只是提供了一种额外的语法。不过 XAML 语法是方便工具创建和使用而设计的,这样的工具能够使设计人员直接进行用户界面设计,而不需要任何编码技能。
(有关 WPF 更详细的内容,请查阅 http://wpf.netfx3.com/ )
WPF 不是.NET 框架中第一套用于开发富客户端的 API。Windows Forms 作为它的前辈,是构建在 Win32 的窗口系统之上的.NET 封装层。尽管 Windows Form 在 Win32 之上添加了很多功能,但由于下层 UI 平台的限制,用它进行开发有时依旧会缩手缩脚。WPF 没有构建在 Win32 的窗口系统上,而是构建于 DirectX 之上,这就使得 WPF 能够完全利用起本机显卡的能力。然而 WPF 并非只能用于开发视觉效果非凡的应用程序。
WPF 的最大优势,就是它将许多富客户端的特性集成在同一个平台上,其中大部分的独立特性都单独在其他 UI 技术中出现过。例如,WPF 提供了构建矢量动画和视频的能力,这原本一直是 Flash 所专长的。WPF 提供了传统的 Windows 控件,例如按钮、列表框以及树型控件等等,它们在 Win32 和 Windows Forms 中已经出现了很多年了。此外 WPF 还提供了流式文本布局,这原来是 HTML 的能力(尽管目前 WPF 的文本渲染能力远比 HTML 和 CSS 来的强大)。一些面向 HTML 的技术,例如 JSP 和 ASP.NET,也曾使用过 WPF 中标记 + 后台代码的应用程序构建方式,不过它们只能提供最简单的 3D 支持,但是 OpenGL 和 DirectX 长久以来就拥有强大得多的 3D 渲染能力。
WPF 之前的技术都能各自独当一面,但是很难在同一个应用程序中使用不同的技术。例如,我们很难在 Windows 的按钮和下拉菜单中使用 Flash 的动画功能(Flash 应用程序一般使用自行开发的控件,但是它们很难与操作系统的当前主题进行统一,可用性也比较差,而它们的行为一般也和真正的控件不同);我们也很难同时利用 HTML 中的流式文本布局和富客户端中的数据绑定技术。一般说来,如果您希望混合使用不同的技术,您的应用程序需要被分割为多个独立部分,而这几个部分之间的通信会非常困难,甚至几乎不可能实现。
相反,用 WPF 就容易多了。不幸的是,目前许多展示这种集成能力的 WPF 示例都有些脱离实际。在一个流式布局的文档中嵌入一个普通的 Windows 按钮,再加上一个包含立方体的标题,这个立方体还被一个完整的视频动画包裹起来,这种做法的确能够说明同时使用不同的 UI 特性并非难事,但问题是,有谁会设计开发这样一个应用程序呢?
事实上,您一般不会将所有的 UI 功能集成在一个应用程序中。这么做很容易让人想起早期的 Web,许多站点都不假思索地利用所有可能的 HTML 特性。这种做法相当可怕,很长时间以后人们才了解该如何使用合适的技术来构建优秀的 Web 应用程序。同样道理,将 WPF 的各种可视化特性进行随意组合的确无比强大和灵活,但是使用其中有限的几种已经足够开发出有用的应用程序了。而且对于视觉效果一般的应用程序开发,WPF 也提供了许多有用的支持。
如果要令人信服地讨论为什么要使用 WPF 构建前台,我们需要将其和其他可选方案进行一番比较。一些常见的候选技术为 Web、Swing、Flash、Windows Forms 甚至是 Win32。
与 Web 前台相比,WPF 的交互性更强。近来构建交互式 Web 应用程序的标准有所提升,但是尽管 AJAX 与经典的 HTML 相比大大提高了交互行为,它在某些时候仍然显得不够。可能我们已经习惯 Web 应用程序低劣的交互性,因此我们遇到操作性不太差的 Web 应用程序就会心满意足了。即使是用于体验最好的 AJAX 应用程序,以富客户端的标注来看也能算是一般。此外,尽管 AJAX 工具发展迅猛,开发一个交互体验令人满意的 AJAX 应用程序所花费的精力,比使用富客户端技术开发一个差不多的应用程序依旧要高不少。同时 WPF 应用程序还能够在客户机与网络断开的情况下工作。解决 Web 应用程序这方面问题的举措已经开始了,不过到目前为止,不稳定连接下的最佳解决方案还是使用富客户端应用程序。
与 Swing 相比,WPF 有两个显著的优势。首先是 WPF 的数据绑定系统,尤其是稍后会提到的 XML 绑定以及数据模版特性。第二个优势则是把双刃剑,您可能会因此放弃使用 WPF,那就是 WPF 是为 Windows 平台设计和运行的。这意味着 WPF 能够充分利用本地 PC 的各种能力,尤其是图像硬件的能力。这能使某些特性能够更好的运行,例如高级数据可视化的高性能呈现能力,或使用动画或视频作一些装饰性的点缀。
尽管 Flash 能够提供一些与 WPF 类似的装饰能力,例如动画和视频重放,但是如果您希望构造外观和行为与普通 Windows 应用程序相似的应用程序就有些困难了。WPF 的重要特性之一,就是它既提供了高级视觉效果,也提供了用户熟悉的标准 Windows 控件。
WPF 的最大阻碍可能就是客户端缺少.NET 3.0 框架。一个 WPF 应用程序只能在安装了.NET 3.0 框架的机器上运行。如果您希望应用程序能支持非 Windows 操作系统,或者 Windows XP SP2 之前的 Windows 操作系统,那么 WPF 自然已经出局了。而且就算客户机使用了合适版本的操作系统,也可能无法安装.NET 3.0。
(即使您将 WPF 排除在外,您也可以尝试使用 WPF/E,这是一个拥有 WPF 功能子集的 UI 平台。字母“E”代表“Everywhere”,因为它能在非微软平台上运行,包括 FireFox 浏览器和 Mac OS X。不过它目前还没有发布,功能有限。事实上,在写这篇文章的时候 WPF/E 只是刚刚发布了一个公开预览版本,因此 WPF/E 还需要发展,并非一个您可以立即使用的开发平台。)【译者注:这篇文章写于 Silverlight 2 发布之前,虽然技术有些过时,但是本文思想依然值得学习。】
另一个需要考虑的问题是 WPF 应用程序的内存问题。对于目前运行在我机器上的 WPF 应用程序来说,凭他们工作集的大小,都可以和 Microsoft Office 套件中的应用程序争夺“首席内存大户”的头衔了(很明显,这些 WPF 应用程序的功能要比 Office 套件中的任意一个都要少很多)。如果您需要支持小内存配置的客户机,WPF 可能不是最好的选择。
您可能也想了解采用其他的技术的可行性。如果您已经使用.NET,那么 WPF 就显得非常合适了,因为它也是.NET 中的一员,相对比较容易学习和使用。但是如果没有使用.NET 构建过其他系统,您就需要考虑采用 WPF 所获得的优势是否值得开发人员掌握一们新的技术。
如果以上的问题对您来说都不成障碍,它的优势看上去也值得投入,那么您的下一步工作就是考虑您应该构建什么类型的 WPF 应用程序。
WPF 应用程序有几种形式。它们可能拥有一个 Web 形式的导航栏,或者更像一个传统的窗口形式的 UI。它们可能是一个独立的应用程序,可能整个运行于一个浏览器框架(frame)中。而 WPF 应用程序的部署方式也有多种选择。
一个富客户端应用程序的传统样式是拥有自己的窗口,而不是在一个 Web 浏览器中。它们可以从开始菜单的程序列表中打开。您可以使用这种形式,同时使用一个 Web 应用程序来进行更新:WPF 能够使用.NET 框架的“ClickOnce”部署技术,使得应用程序的更新能够通过 Web 浏览器进行,它们会被自动下载到客户机上。
如果您已经有了一个基于 Web 的 Java 应用程序,一个独立的 WPF 应用程序看上去就会有些不合适。在这种情况下,您可能就会选择构建一个或多个运行于浏览器中的导航式的 WPF 应用程序,而不是破坏原来完整的应用程序结构。这种应用程序叫做“XBAP”——一个 XMAL 浏览器应用程序(正如之前提到过的,XAML 是一个标记语言,用于构建 WPF 用户界面)。这是一个与 Java Applets 类似的模型:一个 XBAP 能够内嵌在一个网页中,或者作为一个完整的 Web 页面出现,而这两种情况都会运行于一个安全沙盒(secure sandbox)中。在客户机没有安装.NET 3.0 的时候,您可以将 Web 应用程序中的 XBAP 部分替换为传统的 Web 页面。
另一个选择是使用纯粹的标记方式。除了使用 XBAP 之外(它们会编译成应用程序),您也可以使用 XAML。如果一个 Web 服务器提供 XAML 页面,同时客户端也支持 WPF,那么 XAML 就会被解析并生成内容。通过这种做法可能就会得出一个非常简单的方式来使用 WPF 内容:如果 Web 服务器中的内容管理系统(CMS,Content Management System)支持通过 XSLT 生成 Web 页面的话,您可能可以利用这个特性把相同的资源来同时转化为 HTML 和 XAML。
如果您从头构建一个全新的应用程序,这种小块采用 WPF 的方式并没有太大用处。在这种情况下您可能应该选择独立的客户端应用程序。不过这样就产生了新的问题,就是这样的程序应该如何与一个 Java 服务进行通信。
WPF 是.NET 3.0 框架的一部分,而框架中也包含了 WCF(Windows Communication Foundation 是一个用于开发和使用分布式服务的技术,它支持数量可观的 Web 服务标准)。于是我们得到了一个非常明显的策略,可以将一个 WPF 客户端连接至 Java 服务器:在客户端使用 XML Web 服务。不过这并不是唯一的选择(不过最好还是使用 WCF,可惜在某些情况下您无法使用 WCF。例如目前 WCF 不能支持部分信赖的场景,这意味着它不能在 XBAP 中使用)。
您也可以在客户端使用.NET 2.0 的方式来连接 Web 服务,WPF 的数据绑定系统能够同时支持 WCF 和这种方式。事实上,数据绑定系统完全不会关心这些数据从何而来。您也可以使用一些传统方式作为数据源,例如对象集合。
除了将对象作为数据源之外,WPF 还对直接绑定 XML 数据有着极好的支持。这使 POX(Plain Old XML)方式变得完全可行。下一部分将会展示一个简单的示例。
WPF 能够直接使用 XML 作为数据源而不许要将其转换为其他任何形式。为了展示这个特性,我们来绑定一个非常简单但又很常见的 XML 数据:RSS。世界上有无数 RSS 数据源,它们使用不同的技术生成。在下面的例子中我们会使用 Sun 公司开发人员站点中的 RSS 源(这确保服务器上的数据是使用 Java 生成的)。
<Border BorderBrush="Black" BorderThickness="1" Padding="2"><br></br> <Border.Resources><br></br> <XmlDataProvider x:Key="source" XPath="/rss/channel"<br></br> Source="http://developers.sun.com/rss/java.xml" /><br></br> </Border.Resources><br></br> <StackPanel DataContext="{StaticResource source}"><br></br> <TextBlock Text="{Binding XPath=title}" FontSize="18"<br></br> FontWeight="Bold" Margin="0,5" /><br></br> <TextBlock Text="{Binding XPath=description}"<br></br> TextWrapping="Wrap" /><br></br> </StackPanel><br></br> </Border>
该 XML 数据源的 URL 在这里被硬编码在 XmlDataProvider 元素中,这样可以让示例显得简单一些——在实际的应用程序中,我们可以使用许多不同的方法来获取 XML。
这个例子中最有趣的部分是一对 TextBlock 元素内嵌在了 StackPanel 中(StackPanel 是一个布局组件,它将自身的子元素排列在一个纵向的栈中)。每个 TextBlock 元素将与 XML 数据源的一部分绑定——这种关系使用“{Binding…}”语法来描述。这些元素中的 XPath 表达式都相对于示例中 XmlDataProvider 里的 XPath 表达式,因此第一个 TextBlock 会解析表达式“/rss/channel/title”,并将结果表示为文本。以下是这个示例生成的结果:
在这个例子里我们不需要对 XML 数据作任何处理——我们只需直接将它从 Web 上获取下来即可。WPF 的数据绑定服务让我们使用 XPath 表达直接获取想要展现的数据。这个做法能与任何发布 XML 数据的服务(Java 或其他技术亦可)相结合。
这个例子仅仅展示了 RSS 源中的单一信息。我们只需一点额外的工作就可以生成一些更有意思的东西,因为我们可以利用 WPF 数据绑定功能的另一个特性:数据模版。
数据模版是一个可重用的,用于描述展示一段数据的方式。您可以把同一个数据模版运用在多个项目中,例如一个列表中的多个项目,这样可以让这些项目的展示方式保持统一。下面的例子能被添加到上个例子中的 StackPanel 元素中。下面的代码创建了一个 ListBox 控件,在这个例子中,它的项目与 RSS 源中的每个“item”元素一一对应。
<ListBox ItemsSource="{Binding XPath=item}"<br></br> ScrollViewer.HorizontalScrollBarVisibility="Disabled"><br></br> <ListBox.ItemTemplate><br></br> <DataTemplate><br></br> <Grid Margin="2,8"><br></br> <Grid.RowDefinitions><br></br> <RowDefinition /><br></br> <RowDefinition /><br></br> <RowDefinition /><br></br> </Grid.RowDefinitions><br></br> <Grid.ColumnDefinitions><br></br> <ColumnDefinition Width="80" /><br></br> <ColumnDefinition /><br></br> </Grid.ColumnDefinitions><p> <TextBlock Grid.Row="0" Grid.Column="0" Text="Title:" Margin="0,0,0,6" /></p><br></br> <TextBlock Grid.Row="1" Grid.Column="0" Text="Description:" /><br></br> <TextBlock Grid.Row="2" Grid.Column="0" Text="Link:" /><br></br> <TextBlock Grid.Row="0" Grid.Column="1" FontWeight="Bold" FontSize="14"<br></br> Text="{Binding XPath=title}" TextWrapping="Wrap" /><br></br> <TextBlock Grid.Row="1" Grid.Column="1"<br></br> Text="{Binding XPath=description}" TextWrapping="Wrap" /><br></br> <TextBlock Grid.Row="2" Grid.Column="1" Foreground="Blue"<br></br> Text="{Binding XPath=link}" TextDecorations="Underline" /><br></br> </Grid><br></br> </DataTemplate><br></br> </ListBox.ItemTemplate><br></br> </ListBox>
Each item in the list is presented by a DataTemplate, which in this example has been specified inline inside the ListBox. This template shows how to arrange and format each item, and which pieces of data to extract from the item. The results look like this:
列表中的每个项目都使用同一个 DataTemplate 进行展示,在这个例子中即为 ListBox 里内嵌的 DataTemplate。这个模版展示了排列和格式化每个项目的方式,以及应该如何从每个项目中提取数据。这些做法生成了如下结果:
这个例子仅仅表现了数据模版呈现方式的皮毛。事实上数据模版的表现能力完全不限于文本,您可完全自由地在数据模版中使用 WPF 的任何功能,例如数据模版能够与图片、图像元素、动画或 3D 内容等等一起工作。您也可以添加交互式的控件,例如提供用户可编辑的文本框,或者按照您的想法来表现的自定义控件。
正如您所看到的那样,数据模版提供了一个无比简单的方式,能够轻松地将从外部服务中获取到的列表数据进行格式化呈现。您可以像上面的例子那样将其运用在纯粹的 XML 数据里,您也可以从 WCF Web 服务那里获得数据对象后一起使用。
直接绑定 XML 的能力很有用,不过有时候直接使用封装好的对象会更加方便。如果您正在使用一个提供了 WSDL 定义的 Web 服务,那么您一般可以很容易地借助工具来生成这样一些封装类。
例如,eBay 为它们的 Web 服务提供了 WSDL 定义,您可以通过这个地址来访问: http://developer.ebay.com/webservices/latest/eBaySvc.wsdl (如果您需要使用他们的 API,则必须注册他们的服务,不过您可以自由获取到 API 的 WSDL 定义)。
最早的.NET 版本已经对 Web 服务的访问提供支持了,不过您也可以使用.NET 3.0 中的新增的 WCF 工具。这两种技术会根据 WSDL 中的消息和类型定义生成差不多的封装类。eBay 的 Web 服务 API 中有个 UserType 类型,它提供了单个用户的信息。生成封装类的工具会将 XML 元素的值表示为.NET 类中的属性。我们可以在 WPF 中使用这些属性,例如下面的代码将 UI 与一个 UserType 类的属性进行绑定(这个例子假设程序中其他地方的代码从 Web 服务那里获取了 UserType 对象,并将其放到 UI 的“数据上下文(data context)”中,这样这个对象就可以用于绑定了)。
<Grid TextElement.FontSize="20"><br></br> <Grid.ColumnDefinitions><br></br> <ColumnDefinition Width="Auto" /><br></br> <ColumnDefinition Width="10" /><br></br> <ColumnDefinition /><br></br> </Grid.ColumnDefinitions><br></br> <Grid.RowDefinitions><br></br> <RowDefinition /><br></br> <RowDefinition /><br></br> <RowDefinition /><br></br> <RowDefinition /><br></br> </Grid.RowDefinitions><p> <TextBlock Grid.Column="0" Grid.Row="0" Text="User ID:" /></p><br></br> <TextBlock Grid.Column="2" Grid.Row="0" Text="{Binding Path=UserID}" /><p> <TextBlock Grid.Column="0" Grid.Row="1" Text="Email:" /></p><br></br> <TextBlock Grid.Column="2" Grid.Row="1" Text="{Binding Path=Email}" /><p> <TextBlock Grid.Column="0" Grid.Row="2" Text="Feedback score:" /></p><br></br> <TextBlock Grid.Column="2" Grid.Row="2" Text="{Binding Path=FeedbackScore}" /><p> <TextBlock Grid.Column="0" Grid.Row="3" Text="Registration date:" /></p><br></br> <TextBlock Grid.Column="2" Grid.Row="3" Text="{Binding Path=RegistrationDate}" /><br></br> </Grid>
请注意我们现在已经将绑定表达式指定为“Path=…”而不是之前的“XPath=…”了。WPF 这时就能知道我们希望使用对象的属性,而不是 XML 数据进行绑定。以上的标记会将用户信息生成为如下界面:
在客户端使用封装对象的优势在于容易进行一些除数据表现之外的操作。WPF 应用程序一般都由标记和代码组成,当应用程序从 Web 服务中获得的 XML 封装为对象之后,就可以轻松对数据进行任意需要的处理了。
我们查看了两个简单的例子,它们都是在 Java 服务之上构建了 WPF 前台。我们使用了 WPF 中的数据绑定功能,它提供了一种非常方便的做法,把服务中获取的对象与 UI 连接在一起。和其他富客户端应用程序一样,WPF 应用程序也可以提供我们所需要的客户端智能和行为。在这些例子中,故意使用了较为朴素的视觉效果,来强调 WPF 不仅仅是一个美丽的面孔;WPF 可以首先采用平淡而有用的数据绑定功能和普通的 Windows 控件来完成工作,并在其后为它加上丰富的视觉效果。
如果您需要了解有关.NET 和 Java 集成应用场景的其他内容,请访问 InfoQ 的 J+N 内容页面。
Ian Griffiths 是一个独立咨询师、开发人员、讲师及作家。他写了基本有关 Windows Presentation Foundation、Windows Forms 和 Visual Studio 的书籍。他居住在伦敦,经常在大量的开发人员列表和新闻组中出现,人们经常尝试使用尽可能短的问题来引发他尽可能长的回复,以至于这种做法已经成为一种流行的竞赛。如果您想对他有更多了解,请访问他的博客( http://www.interact-sw.co.uk/iangblog/ )。
查看英文原文: WPF as a Rich Client Technology
评论