BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

把WPF作为一种富客户端技术

| 作者 Ian Griffiths 关注 0 他的粉丝 ,译者 赵劼 关注 5 他的粉丝 发布于 2008年3月26日. 估计阅读时间: 30 分钟 | QCon上海2018 关注大数据平台技术选型、搭建、系统迁移和优化的经验。

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的简单向导

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构建前台?

如果要令人信服地讨论为什么要使用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构建前台?

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)方式变得完全可行。下一部分将会展示一个简单的示例。

XML数据绑定

WPF能够直接使用XML作为数据源而不许要将其转换为其他任何形式。为了展示这个特性,我们来绑定一个非常简单但又很常见的XML数据:RSS。世界上有无数RSS数据源,它们使用不同的技术生成。在下面的例子中我们会使用Sun公司开发人员站点中的RSS源(这确保服务器上的数据是使用Java生成的)。

<Border BorderBrush="Black" BorderThickness="1" Padding="2">
<Border.Resources>
<XmlDataProvider x:Key="source" XPath="/rss/channel"
Source="http://developers.sun.com/rss/java.xml" />
</Border.Resources>
<StackPanel DataContext="{StaticResource source}">
<TextBlock Text="{Binding XPath=title}" FontSize="18"
FontWeight="Bold" Margin="0,5" />
<TextBlock Text="{Binding XPath=description}"
TextWrapping="Wrap" />
</StackPanel>
</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}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="2,8">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition />
</Grid.ColumnDefinitions>

<TextBlock Grid.Row="0" Grid.Column="0" Text="Title:" Margin="0,0,0,6" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Description:" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Link:" />
<TextBlock Grid.Row="0" Grid.Column="1" FontWeight="Bold" FontSize="14"
Text="{Binding XPath=title}" TextWrapping="Wrap" />
<TextBlock Grid.Row="1" Grid.Column="1"
Text="{Binding XPath=description}" TextWrapping="Wrap" />
<TextBlock Grid.Row="2" Grid.Column="1" Foreground="Blue"
Text="{Binding XPath=link}" TextDecorations="Underline" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</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服务那里获得数据对象后一起使用。

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">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>

<TextBlock Grid.Column="0" Grid.Row="0" Text="User ID:" />
<TextBlock Grid.Column="2" Grid.Row="0" Text="{Binding Path=UserID}" />

<TextBlock Grid.Column="0" Grid.Row="1" Text="Email:" />
<TextBlock Grid.Column="2" Grid.Row="1" Text="{Binding Path=Email}" />

<TextBlock Grid.Column="0" Grid.Row="2" Text="Feedback score:" />
<TextBlock Grid.Column="2" Grid.Row="2" Text="{Binding Path=FeedbackScore}" />

<TextBlock Grid.Column="0" Grid.Row="3" Text="Registration date:" />
<TextBlock Grid.Column="2" Grid.Row="3" Text="{Binding Path=RegistrationDate}" />
</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

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

拜年啦!新年快乐! by java fams

拜年啦!新年快乐!
马上就过年了!首先在这里祝大家新年快乐。同时给大家送上一段视频教程!非常新的!很快就可以学会,简单的编程,地址是v.youku.com/v_show/id_XNjY4OTQwMDA=.html

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

1 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT