当我们编写WPF(Microsoft Windows Presentation Foundation)应用程序时,通常会花很长的时间来创建进程对象Application 与 窗体对象 Window。一个简单的WPF 应用程序可能是这样的:
SayHello.cs |
//----------------------------------------- // SayHello.cs (c) 2006 by Charles Petzold //----------------------------------------- using System; using System.Windows;
namespace Petzold.SayHello { class SayHello { [STAThread] public static void Main() { Window win = new Window(); win.Title = "Say Hello"; win.Show();
Application app = new Application(); app.Run(); } } }
|
我想你应该熟悉 System命名空间(如果你不熟悉的话,你可以读 www.charlespetzold.com 上的一本叫 .Net Book Zero的在线书籍), 在该示例程序 SayHello中,使用了using 语法引用了 System.Windows命名空间,在该命名空间中包括了所有的WPF基础类,结构,接口,委托及枚举类型,当然,也包括示例程序中的Application与Windows 类定义。 其它的一些WPF namespace 空间一般以System.Windows为前缀,如System.Windows.Controls, System.Windows.Input及System.Windows.Media。一个值得注意的例外是命名空间System.Windows.Forms,这是一个主要的窗口框架命名空间,除了System.Windows.Forms.Integration,所有以System.Windows.Forms为前缀的命名空间都是System.Windows.Forms的命名空间中。
在本书中,示例程序有一个统一的命名规则,所有的程序都是一个Microsoft Visual Studio 工程,所有的代码都被包含在一个命名空间中。每一个类都有一个单独的源文件,并且其类名通常与文件名一致,如果工程只包含一个类,像前面的示例程序一样,该类名通常与工程名一致。
在所有的WPF进程中, 【STAThread】属性必须被设置在Main函数之前,否则C#编译器会抱怨的,这个属性将设置进程的初始线程的线程模型为单线程模型,这是与COM组件交互所要求的。
在SayHello程序中, Main函数创建了一个标准的进程窗口, 它的Title属性表示窗口标题栏上的文本内容,调用Show方法来显示该窗口。
最后,最重要的一步是调用Application对象的Run方法。在Windows编程模型中,该方法会创建一个消息循环,使得进程可以接收用户的键盘与鼠标输入,如果进程在平板电脑上运行,进程还可以接收触摸板的输入。
另外,你可以通过在Visual Studio 2008创建 C#控制台窗口来建立SayHello示例程序
当你关闭由SayHello工程创建的窗口时,你会发现有个控制台窗口仍然在运行。你可以在工程的属性页来控制是否显示该控制台窗口。现在你可以打开进程的属性页,注意 OutType被设置成Console Application,更改OutPut Type值为Windows Application, 这样程序运行时将不会再显示控制台窗口,我个人认为这个控制台程序在软件开发过程中非常有用,在进程运行过程中,我可以用它来显示一些文本信息以供调试。如果程序无法显示窗口,或者进入了死循环,可能通过Ctrl+C轻松时结束进程。
在SayHello程序中,类Windows 和 Application 都继承自DispatcherObject,但Windows的继承层次更高,如下较所示
Object
DispatcherObject (abstract)
Application
DependencyObject
Visual (abstract)
UIElement
FrameworkElement
Control
ContentControl
Window
当然,现在并没有必要去熟悉这些类的继承结构,但时,随着你不断地编写WPF程序,你会不断地碰到这些类。
程序可以只创建一个Application对象,但是在调用Run函数之后,它就会阻止其它的代码执行。Application对象是不可见的, 但Window对象却可以显示在屏幕上,尽显其美丽。Windows对象有由Title属性标识的标题栏,在这个标题栏的左边有一个系统菜单图标,其右边有最小化,最大化及关闭图标,在该窗口的内部的一大块都是客户区。
实际上,你可以调整SayHello程序中Main方法的语句顺序使其正常工作,例如,你可以将设置Title属性值的语句放置在Show方法之后。理论上,这个改动会使得窗口在显示开始时没有标题,但随后在执行Title属性赋值语句时,才会显示窗口的标题,但这个变化太快,我们将难以观察到。
你可以在创建Window对象之前创建Application对象,但是Run函数应该在最后被调用,在窗口被关闭之前,Run方法是不会返回的。Main方法结束时,Windows对象将会被清除。如果你不调用Run方法,Window对象仍被创建及显示,只是在Main方法结束之后立即被销毁罢了。
除了显示地调用Window的Show方法之外,你可以将Window对象作为参数传递给Run方法:
app.Run(win);
在这个函数中,Run方法将自动调用Windows对象的Show方法
在调用Run函数之前,程序并不算真正运行起来,只有程序运行启来之后,Window对象才能响应用户输入。当用户关闭窗口时,Run方法返回,此时,进程也随之结束。因此,在整个进程的生命周期中,大部分里时间中都在Run方法中。但如果进程一直在Run方法中,它又该如何做其它事呢?
在进程初始化后,进程的职责就是响应消息,这些消息通常是键盘,鼠标或触摸板的用户输入消息。在界面控件元类中定义了一系列的键盘,鼠标及触摸板事件。Window类继承了所有的这些事件。其中有一个事件名为MouseDown, 当用户使用鼠标点击窗口客户区时,该MosueDown事件被触发。
接下来的示例程序HandleAnEvent,调整了Main方法中的语句,并且在窗口中设置了一个MouseDown的事件响应处理函数。
我习惯于将事件处理函数命名为类名+On+事件名,如(WindowONMouseDown),但你可以按你的习惯命名。