作者:刘树伟
QQ:1584793892
查看完整内容及示例代码,请访问:www.iuishop.com
本章讲解了app类与window类的关系。一般情况下,每个程序都会有一个app类和一个或多个window类,app类负责消息循环,window类负责窗口显示。但当window以ShowDialog出现时, 可以不需要app类。这点与MFC程序不同。
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(); // 类似于进入消息循环,如果不执行这一行, 窗口仍然会显示,但一瞬间就消失了。Run方法只有在关闭窗口后,才返回。
}
}
}
基本的WPF程序需要System和System.Windows两个命名空间。
Main函数前面必须有个[STAThread]属性。否则运行里会有错误。
默认工程显示窗口的时候, 还显示一个控制台窗口。这是因为工程配置中,输出选项设置为“Console Application”,改成“Windows Application”就可以了。
win可以不调用Show方法, 而是直接当作参数传递给Run方法来显示: app.Run(win);
MessageBox.Show("aaa");可以显示一个内容为"aaa"的消息框,并且直到按下“OK”按钮后才返回,MessageBox不必定义对象,就可以直接调用Show来显示。
上面的代码中。app和win表面看起来没有任何联系。那么app.Run里,是怎么知道win的呢。答案是Application具有一个static property,名为Current, 也包含一个名为MainWindow的instance property.利用些属性,就可以得到Window对象:Window win = Application.Current.MainWindow;这个不需要显式的把win赋值给MainWindow(在MFC中, 是需要赋值的)。如果在Main中创建了多个Window对象,那么第一个被创建的对象会作为MainWindow,与它们Show的次序无关。
WPF的事件和事件处理器,相当于MFC中的消息和消息响应函数。
WPF中响应某个事件,可以为事件安装事件处理器,例如:win.MouseDown += MyWindowOnMouseDown;(MyWindowOnMouseDown需要自己定义并实现)。在MFC中。是通过消息映射表来实现的。
WPF中响应某个事件的另一种方法是:定义一个派生类。因为基类中,这些事件的事件处理器(响应函数)都已经定义并实现,你只需在你的派生类中。override这些接口就可以了。
如果win调用ShowDialog来显示窗口,那么可以不需Application类。因为ShowDialog有自己的消息循环,不需要Application类的Run方法来处理消息。
Window的派生关系:
Object
DispatcherObject (abstract)
Application
DependencyObject
Visual (abstract)
UIElement
FrameworkElement
Control
ContentControl
Window
InheritTheApp.cs
//----------------------------------------------
// InheritTheApp.cs (c) 2006 by Charles Petzold
//----------------------------------------------
using System;
using System.Windows;
using System.Windows.Input;
namespace Petzold.InheritTheApp
{
class InheritTheApp : Application
{
[STAThread]
public static void Main()
{
InheritTheApp app = new InheritTheApp();
app.Run();
}
protected override void OnStartup(StartupEventArgs args)
{
base.OnStartup(args);
Window win = new Window();
win.Title = "Inherit the App";
win.Show();
}
protected override void OnSessionEnding(SessionEndingCancelEventArgs args)
{
base.OnSessionEnding(args);
MessageBoxResult result = MessageBox.Show("Do you want to save your data?", MainWindow.Title, MessageBoxButton.YesNoCancel, MessageBoxImage.Question, MessageBoxResult.Yes);
args.Cancel = (result == MessageBoxResult.Cancel);
}
}
}
InheritTheApp类从Application派生,并且overrides了OnStartup和OnSessionEnding方法。程序中,Main方法没有创建Application类型对象,而是创建了InheritTheApp类型的对象。然而Main是这个类的一个成员,它看上去像创建了一个属于这个类的实例,但是它是完全合法的,因为Main被定义成static的了。Main方法甚至在InheritTheApp对象还没有被创建时就存在了。
如果想为程序提供命令行参数,Main的定义格式如下:
public static void Main(string[] args)
在Application::OnStartup中,也可以利用StartupEventArgs参数的Args property,取得些字符串数组。
WPF中,对话框和普通窗口,都使用Window类。只是它们显示的方式不一样:普通窗口通过Show方法来显示,对话框通过ShowDialog来显示。这类似于LibUIDK中CUIWnd的做法。
Application还有一个Windows(复数)的property,类型为WindowCollection。此类型包含一个名为Count的property, 且具有一个indexer。只要窗口调用过Show,且还存在,你可以用此indexer取得特定窗口,如Windows[0]会得到第0个窗口。
要使窗口不在任务栏。只需把窗口的ShowInTaskbar属性设置为false就可以了。
可以通过指定窗口的Owner属性,来把窗口作为其它窗口的子窗口,这样,子窗口相当于非模式对话框。这种类型的关系与传统的父子关系不同,设定了Owner的窗口, 可以移动到作为Owner窗口之外,也拥有自己的任务栏图标。不过一定位于Owner窗口之上。当Owner被关闭时,它也会一起被关闭。当Owner被最小化时,它也会一起被最小化。
Window的Width和Height属性一开始都是没有定义的,如果你在程序中没有设定这两个属性,那么它们就会一直没有定义,即使窗口以一定的宽和高被显示出来之后,它们的值也是NaN。你如果要取得实际的尺寸,不要使用这两个属性,而是改用ActualWidth和ActualHeight这两个只读属性。不过要注册的是, 这两个属性在窗口创建过程中,可能为0,只有显示出来后, 才生效。
想要让窗口在显示的时候居中,可以利用Window类的WindowStartupLocation属性。把它的值设置为WindowStartupLocation.CenterScreen就可以了。 类似于MFC的CenterWindow,虽然名字是CenterScreen,但实现是放在工作区的中央,而非屏幕中央。另一个值是CenterOwner,是放在Owner的中央。
Window的派生类处理Key Down消息:
using System;
using System.Windows;
using System.Windows.Input;
namespace XXX
{
class HelloMFC : Window
{
[STAThread]
public static void Main()
{
Application app = new Application();
app.Run(new HelloMFC());
}
protected override void OnKeyDown(KeyEventArgs args)
{
base.OnKeyDown(args);
if (args.Key == Key.Up)
{
Window win = new Window();
win.Show();
}
}
}
}
WPF把按键的枚举定义在了Key类中。如果你想知道键盘按钮时的实际Unicode字符,你应该Override OnTextInput, 它的参数TestCompositionEventArgs的参数的Text属性,是一个Unicode字符串,一般情况下,只有一个字符,但语音和手写输入时,也可能调用OnTextInput,这种情况下,字符串可能稍长一些。