当前位置:文档之家› WPF开发入门

WPF开发入门

WPF开发入门
WPF开发入门

9.1.1 什么是WPF

Windows Presentation Foundation(WPF)是Microsoft在.NET 3.0中推出的一个重要新特性,它为Windows下应用程序开发提供一套全新的显示系统,旨在为用户提供方便的用户操作和震撼视觉体验的界面。WPF支持一套完整的应用程序开发功能,包括应用程序开发模型、资源、控件、图形、动画、布局、数据绑定、文档读写、本地化、安全性等。

WPF的核心是一个与分辨率无关的基于向量的呈现引擎,旨在充分发挥现代图形设备的优势,WPF开发和C#集成可以通过Visual Studio 2008非常方便地进行应用程序开发。WPF和公共语言运行环境(CLR)的完全集成,充分利用了CLR提供的类型安全、跨平台等特性。另外,WPF在CLR之上提供自身的程序模型和类库,如图9-1所示为MSDN上介绍的WPF 体系结构。其中,PresentationFramework和PresentationCore都是基于CLR之上,以托管代码的方式公开应用程序开发接口(API)的。而milcore则在CLR之下,是以非托管代码方式,直接和DirectX紧密集成的,可以充分利用DirectX在图形处理上的巨大便利和性能优势,从而为用户提供具有震撼视觉感受的用户界面。milcore是WPF隐藏于CLR之下的核心驱动组件,在实际应用程序开发中不太可能访问到,这里不再进一步介绍。

WPF体系结构中一个重要原理就是--基于属性,WPF提供的类库、操作方式等都尽可能使用属性,而不是方法或事件。因为属性是声明性的,较之方法和事件更加容易指定对象的意图(这在XAML中相当重要),所以属性系统是WPF体系结构中一个重要部分。在WPF 属性系统中,属性可以被继承和监视,当属性被更改时,属性联系的双方都被通知。由于被继承,所以子元素可以感受到父元素属性的变化,例如,父窗体的窗体大小属性被更改时,会自动通知到子窗体,并同步刷新界面。WPF属性系统的根本是System.Windows. DependencyObject类型,它是WPF属性系统的基类。

在WPF中,System.Windows.Media.Visual类型提供了界面元素的显示支持,它用于生成一个可视化树,树中每个元素都包含特定的绘制和实现能力,从而将需要的数据显示到界面。另外,Visual类还将托管的WPF组件和非托管的milcore组件链接到一起,通过在屏幕上定义一个矩形显示区域来提供显示框架,从而将可视化树中各元素呈现到屏幕上。

WPF中大部分类都是从UIElement、FrameworkElement、ContentElement、Framework ContentElement 4个类派生而来,这4个类称为基元素类。其中,UIElement是主要类,它是从Visual类派生而来,适用于支持大型数据模型的元素,这些元素用于在可以称为矩形屏幕区域的区域内进行呈现和布局,在该区域内,内容模型特意设置得更加开放,以允许不同的元素进行组合。

在WPF中,改变了传统Windows窗体应用程序中的窗体中相对位置计算的布局模式,在WPF中的布局更像网页上元素的布局,显得更加灵活。WPF支持5种常用的布局形式,如表9-1所示。

表9-1 WPF中的常用布局模式

模式说明

Canvas 定义一个区域,在此区域内,可以使用相对于Canvas 区域的坐标显式定位子元素,类似于传统的Windows窗体程序中相对坐标的布局方式

DockPanel 定义一个区域,在此区域内,可以使子元素互相水平或垂直排列,对于简单的单行或单列元素布局比较适用

Grid 定义由行和列组成的灵活网格区域,类似于网页开发中的网格布局,对于比较复杂而灵活的界面布局比较适用

StackPanel 沿水平或垂直方向将子元素排列成一行,对于简单的行或列布局比较适用

WrapPanel 从左至右按顺序位置定位子元素,在包含框的边缘处将内容断开至下一行,后续排序按照从上至下或从右至左的顺序进行,具体取决于Orientation属性的值

表9-1中列出的布局模式实际是不同类型的面板控件,这些面板本身可以装入其他类型的面板,这样就可以得到不同布局模式的组合,从而构建丰富灵活的应用程序界面。例如,在一个Grid面板的各单元内放入Canvas面板,就可以得到整体为Grid布局,但内部却是绝对位置布局的界面样式。

除了在窗体布局上的更改之外,WPF支持动画、二维图形、三维图形等图像处理和多媒体技术,另外,WPF还支持文档的打开和阅读等。由于篇幅限制,这里不再详细介绍。总之,通过WPF可以轻松开发出具有丰富UI的应用程序。

9.1.2 WPF开发模式

Windows Presentation Foundation(WPF)通过Visual Studio 2008提供了一套新的应用程序开发模式,该模式与https://www.doczj.com/doc/401160481.html,网页开发模式有几分相似之处,也是一种前后台开发模式。本节简单介绍一下这种开发模式的一些基本概念。

和普通的Windows窗体应用程序一样,WPF应用程序的开发也分界面设计和后台代码两个部分,WPF应用程序界面设计代码和https://www.doczj.com/doc/401160481.html,页面(见本书第19章)相似。WPF的界面代码是一种新的标记性语言--XAML,后台代码则是C#、https://www.doczj.com/doc/401160481.html,等.NET高级语言(本书实例中都使用C#)。

XAML可以理解成一种特殊的XML文件,因为它的格式和XML一致,但是,根据节点的不同意义,XAML节点可以描述不同的界面元素,所以XAML被用作WPF的UI编写语言。XAML简化了为.NET Framework编程模型创建UI的过程,XAML文件是指通常使用.xaml 为扩展名的XML文件。

在XAML中,界面上的每个UI元素都是一个节点,该节点包含多个子节点,每个子节点表示了父节点所包含的一个UI元素,从而就可以体现出UI上的控件等元素的布局方式。开发人员可以使用代码隐藏文件将UI定义与运行时逻辑相分离。与普通的XML不同,XAML 直接呈现托管对象的实例化,这种常规设计原则简化了使用XAML创建的对象的代码和调试访问。

XAML具有一组规则,这些规则将对象元素映射为类或结构,将XML节点的属性(Attribute)映射为类的属性(Property)或事件,并将XML命名空间映射为CLR命名空间。XAML 元素映射为引用的程序集中定义的https://www.doczj.com/doc/401160481.html,类型,而属性(Attribute)则映射为这些类型的成员。

示例代码9-1演示了一个简单的WPF窗体的XAML代码,层次大致是,一个Windows窗体包含一个Grid,Grid内部包含一个Label 控件和一个Button控件。其中Windows窗体映射到后台代码中的类为HelloWPF.Window1,标题为Title属性的值--HelloWPF,对象名称(Name属性)为FrmMain等。另外,Button控件的名称为btnShowMsg,Click事件处理函数为btnShowMsg_Click()。

示例代码9-1:

xmlns:x="https://www.doczj.com/doc/401160481.html,/winfx/2006/xaml"

Title="HelloWPF" Height="179" Width="262" Name="FrmMain">

VerticalAlignment="Top">Hello WPF, I'm coming !

在WPF应用程序中,与XAML所描述的UI界面对应,还包含一个后台代码文件,本书用C#语言开发,名称为XAML文件名后面添加.cs后缀名,如示例代码9-1对应的XAML文件名称为Window1.xaml,对应的后台代码文件名为Window1.xaml.cs,如示例代码9-2所示为与示例代码9-1对应的后台代码。

其中,类Window1从Window类继承,对应到示例代码9-1中的FrmMain窗体所使用的类,btnShowMsg_Click()方法则对应到示例代码9-1中btnShowMsg的Click事件处理函数。这两个代码文件相互关联,并且一一对应,一个发生修改必须同时修改另外一个。

示例代码9-2:

namespace HelloWPF

{

///

/// Window1.xaml 的交互逻辑

///

public partial class Window1 : Window

{

public Window1( )

{

InitializeComponent( );

}

private void btnShowMsg_Click(object sender, RoutedEventArgs

e)

{

MessageBox.Show("Hello WPF, I'm coming !");

}

}

}

9.1.3 WPF应用程序

Windows Presentation Foundation(WPF)旨在提供用户界面应用程序开发框架,所以基于WPF的应用程序多为用户界面程序。Visual Studio 2008集成了WPF开发支持,提供下面4种类型的WPF应用程序创建向导。

WPF应用程序:也称WPF独立应用程序,创建一个在客户端直接运行的独立的应用程序,和Windows窗体应用程序类似。

WPF浏览器应用程序:创建一个可以承载在浏览器(IE6、IE7及以上版本)之内的应用程序,可以进行页面导航,但是和Web页面不一样。

WPF用户控件库:创建包含开发人员自行开发的WPF用户控件类库。

WPF自定义控件库:创建包含开发人员自行开发的自定义控件类库。

这些应用程序类型都包含在"C#"→"Windows"分类中。其中,WPF独立应用程序和WPF浏览器应用程序都比较常用,而控件库应用程序则多用在需要自行开发并发布独立的用户控件

类库中。

一个可执行的WPF应用程序通常需要一组核心功能,包括创建和管理通用应用程序基础结构、跟踪应用程序的生命周期、检索和处理命令行参数、处理资源文件、拦截未处理异常、返回退出代码等。另外,一个WPF应用程序除了可执行文件之外,还需要其他外部文件的支持,这些文件主要有资源文件、内容文件、源站点文件3类。

WPF应用程序的资源文件和Windows窗体应用程序的资源文件一样,在程序开发时期准备,并且被编译到应用程序内部。

内容文件则是独立于应用程序的文件,但是应用程序运行时这些文件是必需的,例如应用程序配置文件、数据库文件等。这些文件在发布时与应用程序一起发布,在开发期间不一定存在,但在应用程序编译时肯定存在,因为它们会被Visual Studio 2008自动移动到目标目录中。

最后,源站点文件是在编译时无法确定是否存在的文件,这些文件可能保存在远程应用程序中或是保存在远程Web网站上,需要在程序运行时临时从外部站点获取。在WPF应用程序中,如果使用这类文件,必须考虑到文件不存在的情况,并给出相应的处理。

WPF提供了4种类型的应用程序,本章将通过实例详细介绍最常用的两种应用程序--WPF独立应用程序和WPF浏览器应用程序,并将介绍在Visual Studio 2008中如何开发WPF应用程序。

9.2 WPF独立应用程序

WPF独立应用程序是可以在客户端独立运行的应用程序,它在操作界面、运行方式上和Win Form窗体应用程序十分类似,所以也是最常用的WPF应用程序之一,本节将介绍WPF独立应用程序的开发过程、代码结构、窗体和控件的使用等基础知识。

9.2.1 创建WPF独立应用程序

在Visual Studio 2008中,要创建一个WPF独立应用程序,只需根据创建向导执行即可,主要包括下面4个步骤:

(1)打开Visual Studio 2008开发环境,通过选择"文件"→"新建"→"项目"命令打开"新建项目"对话框。

(3),输入项目名称"HelloWPF",选择项目存放位置,并选中"创建解决方案的目录"复选框。

(4)单击"确定"按钮,完成创建向导的设置,Visual Studio 2008会根据模板自动生成WPF 独立应用程序的基本框架以及默认的窗体。

通过Visual Studio 2008自动生成的WPF独立应用程序的代码结构如图9-3所示,其中,包括以下几个主要部分。

Properties:包含应用程序版本信息(AssemblyInfo.cs定义)、资源文件(Resources.resx定义)、配置信息(Settings.settings定义)。

引用:包含WPF应用程序必需的引用,PresentationCore、PresentationFramework是开发WPF 应用程序必需的引用。

App.xaml:应用程序的XAML代码,主导应用程序的启动和退出等,App.xaml.cs是App.xaml 的后台代码。

Window1.xaml:默认启动窗体的XAML代码,Window1.xaml.cs是Window1.xaml的后台代码,该窗体通常根据需要进行修改。

这个结构也是WPF应用程序的典型结构,其中代码文件是可以修改的,XAML代码有可视化设计器,可以轻松地进行界面布局和开发。

WPF应用程序的启动和Window Form窗体应用程序不一样,WPF应用程序是类似于网页的方式执行,每个窗体类似于一个页面,可以进行导航。这从应用程序启动代码可以看出,示例代码9-3是App.xaml的代码,其中表示一个应用程序,它的StartupUri属性表示了应用程序第一次启动的窗体为Windows1.xaml。

示例代码9-3:

xmlns="https://www.doczj.com/doc/401160481.html,/winfx/2006/xaml/presentation"

xmlns:x="https://www.doczj.com/doc/401160481.html,/winfx/2006/xaml"

StartupUri="Window1.xaml">

当一个应用程序中包含多个WPF窗体时,可以修改APP.xaml中的Application节点的StartupUri属性为需要作为主窗体启动的窗体,从而实现从任意窗体启动。

通过代码编辑器编写Window1.xaml和Window1.xaml.cs的代码分别如示例代码9-1和示例代码9-2所示,最后通过选择"调试"→"启动调试"命令生成并执行HelloWPF应用程序,得到的界面如图9-4所示。生成的可执行程序是以.exe作为扩展名的,默认在项目的Bin 目录下。从图9-4中可以看出,WPF独立应用程序和Win Form窗体应用程序产生的效果非常相似,但后台的实现原理完全不同,而且WPF的很多高级技术在Windows窗体应用程序中无法做到,这些将在深入学习WPF之后才能体会到。

9.2.2 WPF窗体介绍

在WPF中,一个独立的窗体用Window来表示,这和Win Form窗体不一样,Window是"窗口"的意思,这很符合Windows视窗系统的初衷。

和Win Form窗体一样,WPF窗体也分成工作区和非工作区两个区域,如图9-5所示,非工作区由WPF自动实现,包括标题栏、图标、最大化按钮、外围边框(白色的边框)、系统菜单。工作区是由WPF提供的一个矩形区域(灰色的矩形),它具体的内容由开发人员根据软件功能具体实现。

在.NET Framework 3.5类库中,所有WPF窗体的基类是System.Windows.Window,该类提供的功能包括绘制窗体、配置窗体外观和管理窗体生命周期等。每个WPF窗体都有一个所

谓的生命周期来表示窗体的存在时间,在窗体生命周期内可以访问,否则不能访问。

WPF窗体的生命周期从窗体对象的实例化开始,然后可以进行重复的打开、激活、停用等操作,最后关闭窗口,退出生命周期,在窗体运行期间,通过捕获用户操作,并以事件机制为开发人员提供响应用户操作的接口。

开发人员在开发一个新的WPF窗体时,主要是对窗体工作区进行设计和编码,包括设置窗体外观、响应窗体事件、设置窗体布局、添加控件、设置控件外观、响应控件事件等。在以后小节中将介绍窗体的具体开发。

9.2.3 修改WPF窗体外观

在Visual Studio 2008中,要修改窗体的外观有通过属性管理器修改、通过XAML代码直接修改和通过C#代码修改3种方法,无论哪一种方法,最终修改的都是该窗体对应的XAML 代码,但通过属性管理器会更加直观。在动态更改界面外观时则通过C#代码修改这种方法。WPF窗体中的每一个界面元素都直接映射到XAML代码中的一个节点,WPF窗体本身也映射到XAML代码中的节点。节点的属性(Attribute)则对应于窗体类的属性(Property),WPF窗体的外观都可以通过属性进行设置。

如示例代码9-4所示是一个窗体的XAML代码,其中节点表示正在描述一个窗体,Class属性则表示该窗体对应的后台代码类型是UseWPFWindow.Window1,通过该属性,编译器"知道"将这个窗体与哪个C#类型相对应,从而完成前后台代码的合并编译。

示例代码9-4:

https://www.doczj.com/doc/401160481.html,/ winfx/2006/xaml/presentation"

xmlns:x="https://www.doczj.com/doc/401160481.html,/winfx/2006/xaml"

Title="示例窗体"Height="300" Width="300" Name="wndMain"

BorderThickness="1"Opacity ="2" WindowStyle="ThreeDBorderWindow" WindowStartupLocation="CenterScreen" Cursor= "AppStarting"

Background="Aquamarine" BorderBrush="Azure" OpacityMask="Aquamarine"

MinHeight= "100" MinWidth="100" Padding="3"

ForceCursor="False" Icon="icon1.ico" IsEnabled="False"

Foreground="Blue" Loaded="wndMain_Loaded">

在示例代码9-4中,除了Class属性外,其他属性都是对窗体外观属性的一些设置,本段代码设置窗体的背景颜色(Background)为蓝绿色(Aquamarine),定义窗体样式(WindowStyle)为三维边框窗体(ThreeDBorderWindow),标题(Title)为"示例窗体",最小高度和宽度都为100像素等。这段代码绘制出来的WPF窗体如图9-6所示。其中最明显的效果是:背景颜色、标题、图标、边框。

注意:由于图9-6是在Windows经典主题下进行截图的,所以三维边框效果不明显,如果是在Windows Vista操作系统下运行该代码,可以得到更加美观的效果,包括标题变成蓝色、三维边框等。

从示例代码9-4可以看出,通过XAML修改WPF窗体的外观非常容易,但XAML设置的外观是静态的,要想动态修改,要用到第3种方法,通过C# 代码修改窗体类属性的值。如示例代码9-5所示,它是示例代码9-4对应的Window1类的代码,其中wndMain_Loaded()方法中通过代码的方式设置窗体标题为"示例窗体--1",设置字体大小为10。

示例代码9-5:

namespace UseWPFWindow

{

///

/// Window1.xaml 的交互逻辑

///

public partial class Window1 : Window

{

public Window1( )

{

InitializeComponent( );

}

private void wndMain_Loaded(object sender,

RoutedEventArgs e)

{

this.Title = "示例窗体--1";

this.FontSize = 10;

}

}

}

开发人员可以为WPF设置多种不同的外观特性,比较常用的属性如表9-2所示,其中包括窗体标题、大小、字体、图标、前景色、背景色、边框样式、光标和右键菜单等,但在实际开发中只是根据需要修改其中的一个或多个即可。

表9-2 WPF窗体属性

属性名说明

Tiltle表示窗体的标题

Icon表示窗体左上角显示的图标

Cursor表示窗体中正常状态下使用的光标类型

WindowState表示窗体处于还原、最大化、最小化中某一种状

WindowStartupLoca tion 表示窗体启动时的位置,可选屏幕中央、父窗体中央、默认位置

WindowStyle表示窗体的边框样式

Width表示窗体的宽度,单位为像素

Height表示窗体的高度,单位为像素

MinWidth表示窗体的最小宽度,单位为像素

MinHeight表示窗体的最小高度,单位为像素

MaxWidth表示窗体的最大宽度,单位为像素

MaxHeight表示窗体的最大高度,单位为像素

Top表示窗体上边沿相对于桌面的位置,单位为像素Left表示窗体左边沿相对于桌面的位置,单位为像素FontFamily表示窗体上的字体,如宋体、黑体等

FontSize表示窗体上字体的大小

FontStretch表示窗体上字体的压缩或扩展程度

FontStyle表示窗体上字体的样式

FontWeight表示窗体上字体的粗细

Foreground表示窗体中用于绘制前景色的画笔

Background表示窗体中用于绘制背景颜色的画笔

BorderBrush表示窗体中用于绘制边框背景的画刷

BorderThickness表示窗体中边框的宽度,单位为像素

Margin表示窗体的外边距

Padding表示窗体的内边距

9.2.4 使用WPF窗体事件

事件是.NET中一种非常重要的消息通知机制,WPF虽然尽量使用属性,但事件同样是必不可少的组成部分。与Win Form窗体一样,WPF窗体也同样具有很多不同的事件,在实际开发中同样需要为这些事件增加事件处理函数。

在WPF窗体的整个生命周期中,下面这些重要的事件控制WPF窗体的执行、显示、用户操作、关闭等关键环节。

Loaded:窗体第一次启动时,需要加载窗体中的内容、空间等,第一次加载完成后引发该事件,通常可以在该事件中进行一些界面以及数据的初始化操作。

ContentRendered:在窗体的内容显示完成后引发该事件。

Actived:在窗体激活(变成前台窗体)时引发该事件。

Deactived:在窗体变成后台窗体时引发该事件。

Closing:在窗体即将关闭时引发该事件,在调用Window.Close()方法请求关闭窗体时引发该事件,可以在事件处理函数中进行关闭前确认、资源释放等操作。

Unloaded:在窗体中的显示元素全部移除之后引发该事件,这时窗体已经接近死亡,同样可以在事件处理函数中进行资源释放等操作。

Closed:在窗体已经关闭之后引发该事件,这时窗体已经关闭,马上结束生命周期,这是最后一次释放资源的机会

示例代码9-6:

https://www.doczj.com/doc/401160481.html,/ winfx/2006/xaml/presentation"

xmlns:x="https://www.doczj.com/doc/401160481.html,/winfx/2006/xaml"

Title="示例窗体" Height="309" Width="308" Name="wndMain"

Icon="icon1.ico" IsEnabled ="True"

Foreground="Blue" Loaded="wndMain_Loaded" Closing="

wndMain_Closing" Closed=" wndMain_ Closed"

Activated="wndMain_Activated" Deactivated="wndMain_

Deactivated" Unloaded="wndMain_ Unloaded"

ContentRendered="wndMain_ContentRendered">

Name="label1" Width="120" FontSize="15"

Foreground="Blue">提示信息

"206" Name="tbHint" Width="251"

HorizontalScrollBarVisibility="Auto"

VerticalScrollBarVisibility="Auto">

在XAML中指定事件处理函数之后,还需要保证对应的后台代码中必须包含对应的函数,否则无法正确编译。如示例代码9-7是与上面代码对应的后台代码,它的功能主要是在事件响应函数中增加提示信息,从而监视这些事件发生的顺序。

示例代码9-7:

namespace UseWPFWindow

{

///

/// Window1.xaml 的交互逻辑

///

public partial class Window1 : Window

{

public Window1( )

{

InitializeComponent( );

}

private void AppendString(string str)

{

this.tbHint.AppendText(System.DateTime.Now.ToString( ) + ":"

+ str + System.Environment.NewLine);

}

private void wndMain_Loaded(object sender, RoutedEventArgs e)

{

this.AppendString("wndMain_Loaded");

}

private void wndMain_Closing(object sender, https://www.doczj.com/doc/401160481.html,ponentModel.CancelEventArgs

e)

{

this.AppendString("wndMain_Closing");

MessageBox.Show("wndMain_Closing");

}

private void wndMain_Closed(object sender, EventArgs e)

{

this.AppendString("wndMain_Closed");

MessageBox.Show("wndMain_Closed");

}

private void wndMain_Activated(object sender, EventArgs e)

{

this.AppendString("wndMain_Activated");

}

private void wndMain_Deactivated(object sender, EventArgs e)

{

this.AppendString("wndMain_Deactivated");

}

private void wndMain_ContentRendered(object sender, EventArgs e)

{

this.AppendString("wndMain_ContentRendered");

}

private void wndMain_Unloaded(object sender, RoutedEventArgs e)

{

this.AppendString("wndMain_Unloaded");

MessageBox.Show("wndMain_Unloaded");

}

}

}

生成并运行示例代码9-6和示例代码9-7,在窗体第一次启动时,首先窗体被激活产生Activated事件,然后是窗体加载需要显示的内容完成,产生Loaded事件,接着是将这些内容显示到界面完成,产生ContentRendered事件。在窗体关闭时,首先产生一个即将关闭的Closing 事件,然后窗体切换到后台窗体,产生Deactivated事件,接着卸载窗体中所有元素完成,产生Unloaded事件,最后窗体彻底关闭,产生Closed事件。

在WPF窗体的整个生命周期中,除了以上介绍的几个主要事件之外,WPF窗体在运行过程中还要产生很多事件,包括鼠标事件、键盘事件、属性变更事件、拖放事件、焦点变更事件、外观变化事件等,理解并合理处理这些事件,可以大大提高应用程序开发的灵活性和多样性。

相关主题
文本预览
相关文档 最新文档