一个为WPF编写的Windows桌面应用程序通常是从创建Application对象和Window对象开始的。下面是一个简单的WPF程序:
![](/Images/OutliningIndicators/None.gif)
2
![](/Images/OutliningIndicators/None.gif)
3
![](/Images/OutliningIndicators/None.gif)
4
![](/Images/OutliningIndicators/None.gif)
5
![](/Images/OutliningIndicators/None.gif)
6
![](/Images/OutliningIndicators/None.gif)
7
![](/Images/OutliningIndicators/None.gif)
8
![](/Images/OutliningIndicators/None.gif)
9
![](/Images/OutliningIndicators/None.gif)
10
![](/Images/OutliningIndicators/None.gif)
11
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
12
![](/Images/OutliningIndicators/InBlock.gif)
13
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
14
![](/Images/OutliningIndicators/InBlock.gif)
15
![](/Images/OutliningIndicators/InBlock.gif)
16
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
17
![](/Images/OutliningIndicators/InBlock.gif)
18
![](/Images/OutliningIndicators/InBlock.gif)
19
![](/Images/OutliningIndicators/InBlock.gif)
20
![](/Images/OutliningIndicators/InBlock.gif)
21
![](/Images/OutliningIndicators/InBlock.gif)
22
![](/Images/OutliningIndicators/InBlock.gif)
23
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
24
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
25
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
26
![](/Images/OutliningIndicators/None.gif)
27
![](/Images/OutliningIndicators/None.gif)
28
![](/Images/OutliningIndicators/None.gif)
你可能非常熟悉System命名空间(如果不是,你应该看一下我的在线书 .NET Book Zero),程序SayHello还包含了一个对 System.Windows 的引用,这个命名空间包含了所有的WPF的基础的东东,包括类、结构、接口、代理和枚举,也包括了程序中用到的 Application 和 Window。其他的WPF命名空间都是以 System.Windows 为前缀的,像 System.Windows.Controls,System.Windows.Input 和 System.Windows.Media。有一个例外是System.Windows.Forms,这个命名空间是主Windows窗体的命名空间。所有的以System.Windows.Forms开始的命名空间都是Windows窗体命名空间,除了Windows.Windows.Forms.Integration,这个命名空间包括了可以帮助你将Windows窗体和WPF代码集成起来的类。
这本书中的所有代码都有一个一致的命名方案。每一个程序都和一个Microsoft Visual Studio工程相关联。工程里的所有代码都被一个命名空间的定义所附。(原文比较罗嗦,就不继续翻译这一段了)
在任何一个WPF程序中,属性[STAThread]必须放在Main函数或者C#编译器将要编译的前面。这个属性指示了程序初始化时的线程模型为一个单线程的套间,这是与COM交互时必须的。“单线程套间”是一个旧的COM时期早于.NET的编程用语。但是还是要这样做。
在SayHello程序中,Main函数开始时定义了一个Window类的对象,这个类可以用来创建一个标准的应用程序窗口。属性Title指示了将要出现在窗口标题栏出现的文字,Show方法则是在屏幕上显示这个窗口。
最后一个重要的步骤是在一个新建的Application对象中调用Run方法。在Windows编程方法中,这个方法创建了消息循环,这允许应用程序可以接收用户从键盘和鼠标的输入。如果程序是运行在一个Table PC中,应用程序也从触摸屏中接收输入。
你可能会用Visual Studio 2005创建、编译和运行为WPF编写的程序。如果是,那么你可以按照如下的步骤创建SayHello程序。
1.在文件菜单中选择新建工程。
2.在新建工程对话框中,选择Visual C#,WPF和空工程。为工程设置一个目录并且起名叫做SayHello,不要选择创建工程目录。点击确定按钮。
3.在右边(或者其他地方)的解决方案资源管理器中,在引用项中加入PresentationCore、PresentationFramework、System和WindowsBase。
4.在右边的解决方案资源管理器中,右键单击工程SayHello的名称,在添加菜单中选择添加新项,在出现的对话框中选择代码文件,键入文件名SayHello.cs,点击确定按钮。
5.键入SayHello.cs文件的源代码(在上边)。
6.选择“开始执行(不调试)”或者直接按下Ctrl+F5键编译和运行程序。
在本书第一部分展示的大部分程序,创建工程都是采用和上述步骤基本相同的方法,除了一些具有多个源代码文件的工程外(本章就有一个这样例子)。
当你关闭SayHello所创建的窗口时,你会发现有一个控制台窗口仍然在运行。这个控制台窗口的出现是受到工程中一个属性的控制的。右键单击工程名字选择“属性”菜单(或者在“工程”菜单中选择“属性”),现在你可以浏览或者修改工程的一些特性。注意在输出类型中是被设置为“控制台应用”。把输出类型改为“Windows应用”后,程序会和以前一样运行,但是不会出现那个控制台窗口。笔者个人发现这个控制台窗口在编程中还是相当有用的。我经常用它在程序运行时显示一些调试用的文本信息。还有一个好处,就是如果你的程序bug太多,甚至不能正常的显示一个窗体,或者陷入一个死循环,那么你可以轻松的在控制台窗口按下Ctrl+C键中止这个程序。
SayHello中用到的Window和Application类都是从DispatcherObject派生而来的,但是Window类有一个非常长的家谱,就像下面展示的类继承图一样:
Object
DispatcherObject(abstract)
Application
DependencyObject
Visual(abstract)
UIElement
FrameworkElement
Control
ContentControl
Window
当然,现在还没到和这些类继承图打交道的时候,但是在学习WPF的过程中间你难免会不断遇到这些个类。
一个程序可以在只有一个Application对象的情况下创建,这个对象可以充当程序其他部分的一直存在的锚。Application对象是不可见的;Windows对象有一个标题栏,标题栏的文本由Title属性指定。标题栏的左边有一个系统菜单,右边还有最小化、最大化和关闭按钮。窗口有一个可以调整大小的边框,并且有一个相当大的客户区域。
在SayHello程序中,你可以改变Main方法的顺序,而程序依然可以运行。例如,你可以在调用Show方法后再设置Title的属性。理论上说,这样改了之后,窗口在初始化的时候标题栏会没有文本,但是很快的就会出现,迅雷不及啊。
你可以在创建Window对象之前创建Application对象,但是一定要在最后调用Run方法。Run方法直到窗口关闭时才会返回。那样的话,Main方法会在你的程序结束之后结束。如果你去掉Run的调用,Window对象也会创建并且显示出一个窗体,但是会立即消失,因为Main函数已经结束了。
代替Window对象调用Show的一个途径是,你可以将Window对象作为一个参数传递给Run方法:
![](/Images/OutliningIndicators/None.gif)
在这种情况下:Run方法自己承担起为Window对象调用Show方法的责任。
一个应用程序直到调用Run方法时才真正开始运行起来。只有这样Window对象才能响应用户的输入。当用户关闭窗体和Run方法返回时,程序才准备退出。Thus, the program spends almost all of its existence deep within the Run call. But how can the program do anything if it is spending all its time in Run?
在初始化之后,实质上程序中所有的事情都是为了响应事件。这些事件有用户的键盘、鼠标或者触摸屏输入。UIElement类定义了一系列键盘、鼠标和触摸屏相关的事件。Window类继承了所有的这些事件。其中有一个事件叫做MouseDown。当用户在客户区单击鼠标时会引发一个MouseDown事件。
下面的程序安装了一个事件处理器,为了处理MouseDown事件:
![](/Images/OutliningIndicators/None.gif)
2
![](/Images/OutliningIndicators/None.gif)
3
![](/Images/OutliningIndicators/None.gif)
4
![](/Images/OutliningIndicators/None.gif)
5
![](/Images/OutliningIndicators/None.gif)
6
![](/Images/OutliningIndicators/None.gif)
7
![](/Images/OutliningIndicators/None.gif)
8
![](/Images/OutliningIndicators/None.gif)
9
![](/Images/OutliningIndicators/None.gif)
10
![](/Images/OutliningIndicators/None.gif)
11
![](/Images/OutliningIndicators/None.gif)
12
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
13
![](/Images/OutliningIndicators/InBlock.gif)
14
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
15
![](/Images/OutliningIndicators/InBlock.gif)
16
![](/Images/OutliningIndicators/InBlock.gif)
17
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
18
![](/Images/OutliningIndicators/InBlock.gif)
19
![](/Images/OutliningIndicators/InBlock.gif)
20
![](/Images/OutliningIndicators/InBlock.gif)
21
![](/Images/OutliningIndicators/InBlock.gif)
22
![](/Images/OutliningIndicators/InBlock.gif)
23
![](/Images/OutliningIndicators/InBlock.gif)
24
![](/Images/OutliningIndicators/InBlock.gif)
25
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
26
![](/Images/OutliningIndicators/InBlock.gif)
27
![](/Images/OutliningIndicators/InBlock.gif)
28
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
29
![](/Images/OutliningIndicators/InBlock.gif)
30
![](/Images/OutliningIndicators/InBlock.gif)
31
![](/Images/OutliningIndicators/InBlock.gif)
32
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/dot.gif)
33
![](/Images/OutliningIndicators/InBlock.gif)
34
![](/Images/OutliningIndicators/InBlock.gif)
35
![](/Images/OutliningIndicators/InBlock.gif)
36
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
37
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
38
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
39
![](/Images/OutliningIndicators/None.gif)
40
![](/Images/OutliningIndicators/None.gif)
我喜欢把我的事件处理程序命名为以类或者对象名字开头,后面跟着单词On,然后跟着事件的名称本身(因此为WindowOnMouseDown)。但是你可以将你的事件处理程序命名为你想叫的名字。
MouseDown事件被提供为一个MouseButtonEventHandler代理的事件处理程序,这个函数第一个参数是一个object类型的对象,第二个参数是MouseButtonEventArgs类型。这个类定义在命名空间System.Windows.Input中,那么程序必须包含这个命名空间。这个程序必须将事件处理程序定义为静态的,因为Main函数是静态函数。
这本书中很多程序将包含这个命名空间,即使用不到。
(待续)