WPF精粹
文/蔡学镛

Windows Vista已经于2007年1月30正式发行零售版本,安装Vista的计算机将会大量出现。在Vista时代,身为编程员,就一定要具备Vista桌面应用开发的能力。而开发Vista桌面应用,最重要的就是要会WPF。本系列文章整理WPF技术的精华,以连载的方式,介绍如何使用WPF编写微软Windows平台。

什么是WPF?
WPF是Windows Presentation Foundation的缩写。WPF是一套API,利用WPF所开发出来程序可以是:
 一般独立执行的Windows应用,也称为client应用。
  或者是分布式(distributed)应用的前端——现在有一个更时髦的名称Rich Internet Application(RIA)。

虽然WPF是编写Windows平台的应用,但WPF应用绝对不同于以往的Windows应用:外在,WPF应用具有崭新的外观和新的图形效果(包含动画和3D);内在,WPF应用具有新的控件设计哲学和新的API。
WPF应用只能在.NET Framework 3.0的环境中执行,计算机上必须安装:
 Windows Vista(自带.NET Framework 3.0)或者
 Windows XP/SP2或者
 加装.NET Framework 3.0的Windows 2003。

如果你是编程员,你的环境除了具备上述的要求之外,还必须配备:
Visual Studio 2005 Professional Edition(商业软件)
 .NET Framework 3.0 and Windows SDK(免费)
Visual Studio Extensions for WCF, WPF(免费)
上列的免费软件都可以从微软的MSDN网站下载,除此之外,Visual C#已推出 Express Edition,也可以免费下载。你可能想要使用免费的Visual C# Express Edition取代Professional Edition,但是Visual Studio Extensions for WCF, WPF只能搭配Professional Edition的Visual Studio 2005。由于Visual Studio 2005(以及Visual C# 2005 Express Edition)内附的.NET Framework SDK是2.0版,所以必须额外安装.NET Framework 3.0,并搭配Visual Studio Extensions for WCF, WPF。估计微软将在2007年底推出新版的Visual Studio,届时只要直接安装Visual Studio就行了,不用像现在这么辛苦,拼拼凑凑地四处下载和安装软件。

如果你无法取得Visual Studio 2005 Professional Edition,也不想安装巨大的Windows SDK(这东西大得吓人,需要1.15GB),那么直接利用免费的VisualC# Express Edition和免费的.NET Framework 3.0即可,一样可以写WPF程序,只是会有两个缺点:
 在Visual C#中没有WPF的template,你必须手动写每一行程序,且手动加入相关DLL的参考。(本文稍后介绍如何加入DLL参考。)
不能使用XAML。

Windows开发技术的历史
Windows已经有22年的历史,这22年来,微软官方主力推行的编程语言与API有四个分水岭:
1985~1991年:C搭配Windows API。目前我们已很少用C和Windows API写程序了,但还是有必要熟悉这样的技术,因为有些特殊的时候会用到。
1992~2001年:C++搭配MFC链接库(这段时间也是Visual Basic最风光的时候)。在历史上MFC是最多人用的Windows编程方法。我很高兴MFC这么糟糕的技术终于淡出历史了!
 2002~2006年:C#搭配Windows Form。这段期间IT技术的焦点是在Web上,所以虽然大家都在用.NET,但真正的主角是ASP.NET,而不是Windows Forms。Windows Forms还没等熬出头,WPF就出现了。Windows Forms注定会是历史中“最少人使用的微软开发技术”。Windows Forms其实是不错的技术,但好技术(Windows Forms)的下场是没人用,差技术(MFC)的下场是大家都在用。我只能说,Windows Forms生不逢时。
2007~今:C#搭配WPF。你可能觉得很奇怪,微软为何释出两个作用相似,却不同且不相容的.NET API。其实,Windows Forms在设计上比较偏向于传统的应用(类似Java Swing),没有考虑到Web/Markup的需求,所以后来微软才会设计全新的WPF。

Windows Form VS WPF VS Apollo
由于Windows Forms已经发展多年,所以控件(control)和标准对话框(dialog box)都比WPF更好,但是未来WPF却很有发展潜力。特别是:

 如果你需要做很多客制化控件和绘图,WPF会比Windows Forms更适合。WPF和Windows Forms在开发时,虽然都可以进行“视觉”和“逻辑”的切割,但是Windows Forms的视觉部分是使用Partial Class,但WPF的视觉部分却是XML(XAML)。XML格式适合不懂编程的美工人员进行处理,微软也会在今年(2007)推出相关的设计工具(Expression)。
 WPF意图利用简化版本WPF/E走进各种装置,包括浏览器和手机。目前Windows Forms虽然可以用在Windows Mobile 5上,但是不能用在浏览器内。而WPF/E可以用在Windows Mobile 6上和各种浏览器内。

Adobe Apollo和WPF是类似的技术。如果你要开发跨平台的应用,当然选择Adobe Apollo(另一个选择是Java Swing,但是在F3语言正式释出之前,我不认为Java是一个好选择),如果你要开发Windows平台专属的应用,当然要选择WPF,因为:
开发应用时,偶而需要呼叫OS的DLL,但Apollo 1.0不允许我们这么做(基于安全的理由)。
如果你确定你的应用不需要跨平台,那么采用操作系统所支持的开发方式,往往可以带来其它的边际效益。例如:用WPF开发Vista应用,可以让应用轻易地兼容于Power Shell;用Cocoa开发MacOS X应用,可以让应用轻易地兼容于AppleScript。

C# VS XAML
一般的WPF应用,都会同时包含:
程序代码(本系列文章使用C#):主要是处理逻辑的部分。
XAML(一种XML语言):主要是处理视觉的部分。XAML的英文发音为zammel。
结合XAML和C#程序代码各自的优点,可以帮助我们建立更大型、更复杂的应用。你可以参考我上一期(2007年2月)的Apollo文章,C#其实就类似ActionScript,而XAML则类似于MXML。任何WPF程序都可以只用C#,不用XAML就开发出来。而只有少部分简单的程序可以只用XAML,完全不使用C#就开发出来。从这个角度来看,C#程序代码才是重点,而XAML只是让我们编程更方便。XAML所叙述的一切,编译时会被转成程序代码。因此,如果你真的想要好好掌握WPF的技术,那么在学习阶段,应该将心思先放在程序代码的部分。每个WPF编程员都应该要对于WPF的程序代码部分建立稳固的根基。

XAML的档案一般是用交互式工具(例如Expression)和编程工具(例如Visual Studio)所产生出来的,我们自然也应该善用这样的工具,毕竟XML本来就是给机器读的。但尽管如此,每个编程员还是有必要具备亲自动手编写XAML的能力。

WPF名称空间
开发WPF应用时,请特别注意下面的名称空间(namespace):
System.Windows:这个名称空间包含了所有基本的WPF类别、结构(struct)、界面(interface)、delegate、以及列举(enum),其中包含了Application与Window类别。WPF的开发应用,一般来说,一开始需要建立Application对象与Window对象。
System.Windows:它的WPF名称空间开头都是System.Windows,例如System.Windows.Controls、System.Windows.Input、System.Windows.Media。
System.Windows.Forms:虽然此名称空间是在System.Windows之下,但是它不属于WPF,而是最基本的Windows Forms名称空间。
其它的Windows Forms名称空间相当分散,包括System.Windows.Forms、System.Drawing、System.ComponentModel。
System.Windows.Forms.Integration:这个名称空间的类别是用来帮助Windows Forms和WPF程序代码之间做整合之用的。

一个简单的WPF应用
Application和Window可以说是最基本的WPF类别,两者皆属于System.Windows名称空间。顾名思义,Application用来代表整个应用,而Window用来代表一个窗口。
在一个应用中,只能建立一个Application对象,对于应用的其它地方来说,此Application对象的作用就如同固定船的锚一般。你在屏幕上是看不见Application对象的,但是可以看得见Window对象。
Window对象出现在屏幕上,就是正常的Windows操作系统的窗口,具有标题列。标题列的系统选单icon是在左边,而最小化、最大化、和关闭窗口的icon是在右边。此窗口具有一个可以调整窗口大小的边框,窗口中间很大的面积被一个client area(客户区)所占据。
基本上,建立最简单的WPF应用就是:
1. 建立窗口
2. 显示窗口
3. 让窗口进入讯息循环(message loop)(透过Application的协助)

其实传统的C/Windows API、C++/MFC、C#/Windows Form也都是这样的步骤。根据上面的三个步骤,编写出下面的WPF程序代码。这个程序代码相当简单,没用到继承:

using System;
using System.Windows;
namespace WPFTest
{
     class Hello
     {
         // 程序进入点
     [STAThread]
     public static void Main()
     {
         // 1. 建立窗口
     Window win = new Window();
     // 设定窗口标题
     win.Title = "Hello";
     // 2. 显示窗口
     win.Show();
     // 建立Application对象
     Application app = new Application();
     // 3. 让窗口进入讯息循环
     app.Run();
     }
     }
}

Main()是程序进入点,至于Main()放在哪个类别中,则无所谓。Main的前面都必须具有[STAThread] attribute,否则编译会失败。[STAThread]是用来指定,初始应用执行绪的执行绪模型是single-threaded apartment。STA是前朝COM时代的技术余孽,不太需要搞懂它,[STAThread]大致上的意思是:我们的应用不会使用源自于“执行期环境”的多执行绪。

在Hello程序中,Main建立一个Window类别的对象,这个类别用来建立标准应用窗口。Title property是会显示在窗口标题列的文字,而Show方法会将窗口显示在屏幕上。
这里最重要的步骤是:呼叫Application对象的Run方法。在传统Windows编程的思维中,这么做的目的是要建立一个讯息循环,让应用可以接收使用者键盘或鼠标的输入。如果此程序是在Tablet PC上执行,此应用也会接收到来自触控笔(stylus)的输入。Run方法一旦被呼叫,就不会返回,直到窗口被关闭为止。然后,Main方法结束,随后Windows操作系统会做一些清除的工作。
Run()有另外一个版本,接收一个Window对象当参数。Run()会检查Window是否已经显示出来,如果尚未显示,Run()会呼叫Window对象的Show()。然后才进入讯息循环,所以这两行程序:

win.Show();
app.Run();

可以简化如下:

app.Run(win);
使用Visual C#

如果你使用Visual Studio 2005 Professional Edition且你有安装WPF extension,那么你可以采取下面的步骤来建立此Hello程序:
1. 从“File”选单,选取“New Project”。在“New Project”对话框中,选取Visual C#、Windows Presentation Foundation和Empty Project,并将项目命名为Hello,然后按下“OK”。
2. 在右边的“Solution Explorer”中,“References”区域必须包含PresentationCore、PresentationFramework、System、以及WindowsBase。如果在此“References”区域中,没有出现这些DLL,请手动将它们加上去,只要用鼠标右键点选“References”,然后选取“Add Reference”就可以了(或者,从“Project”选单中,选取“Add Reference”)。在这个“Add Reference”对话框中,点选“.NET” tab,然后选取必要的DLL,最后按下“OK”。
3. 在“Solution Explorer”中,用鼠标右键点选Hello的项目名称,然后从“Add”选单中选取“New Item”(或者,从“Project”选单中,选取“Add New Item”)。在“Add New Item”对话盒中,选取“Code File”,键入文件名称“Hello.cs”,最后按下“OK”。
4. 将前面的程序代码,键入Hello.cs档案中。
5. 从“Debug”选单,选取“Start Without Debugging”(或者,直接按下Ctrl+F5),就可以编译并执行此程序。

如果你使用Visual C# 2005 Express Edition,步骤和上面差不多,但要特别注意步骤2。你一定要手动将下面的DLL加入:
PresentationCore.dll(版本3.0.x.x)
PresentationFramework.dll(版本3.0.x.x)
System.dll(版本2.0.x.x)
 WindowsBase.dll(版本3.0.x.x)
这些DLL位于GAC(C:/WINDOWS/assembly/)的深层目录中。由于你无法将GAC的DLL加入Visual C#的项目(这是因为shfusion的遮蔽效果,造成Visual C#无法看见GAC内的档案结构),所以你必须先透过“DOS窗口”(命令提示字符窗口),利用dir、cd、copy等指令,将这些档案找出来(这需要花一点时间),复制到某个目录中(例如C:/Assembly/),然后再利用下面的方式将它们加入项目中当参考(references):
1. 在右边的“Solution Explorer”中,用鼠标右键点选“References”,然后选取“Add Reference”;
2. 翻到“Browse”页,找到PresentationCore……等档案的目录,选取这几个档案,然后按下OK。
今后如果需要用到其它.NET 3.0的API,也都可以用上述的方式将它们的DLL加入参考。
关闭与开启Console窗口
在Hello的例子中,你会发现执行时同时会出现一个console窗口,这是因为编译旗标设定的关系,你可以在项目的property中,调整此旗标。做法如下:
1.用鼠标点选右边的项目名称,并从选单中选取“Properties”(另一个作法是,从“Project”选单中选取“Properties”)。
2. 现在你可以检查看看项目的各种设定,也可以改变设定。特别注意,“Output Type”被设定为“Console Application”,显然这样的设定,并不会阻碍console程序更进一步地建立GUI窗口。
3. 将“Output Type”设定为“Windows Application”,这个程序将会和以前一样可以顺利执行,而这次不会再出现console窗口了。

在开发阶段,console窗口有时候是我们的好朋友,因为:
我们可以利用它来显示一些文字信息,以便debug。
如果程序的bug太多,甚至一开始就出问题,而无法将GUI窗口显示出来,或者进入无穷循环,这个时候,只要在console窗口中键入Ctrl+C,就可以轻易地将程序终结。




 
Logo

20年前,《新程序员》创刊时,我们的心愿是全面关注程序员成长,中国将拥有新一代世界级的程序员。20年后的今天,我们有了新的使命:助力中国IT技术人成长,成就一亿技术人!

更多推荐