WPF 开发人员需要知道的一切
41 – 启动和关闭时的窗口事件
在应用程序启动时,为主窗口触发(按顺序)的 Window 事件是:
- 初始化 - 正在创建主窗口
- IsVisibleChanged – IsVisible 属性设置为 true
- SizeChanged – 大小属性设置为窗口的大小
- LayoutUpdated - 窗口布局更改
- SourceInitialized – 窗口附加到 Win32 窗口句柄
- Activated - 窗口变为前景窗口
- PreviewGotKeyboardFocus – 窗口获得焦点
- IsKeyboardFocusWithinChanged – IsKeyboardFocusWithin 属性设置为 true
- IsKeyboardFocusedChanged – IsKeyboardFocused 属性设置为 true
- GotKeyboardFocus - 窗口现在具有键盘焦点
- LayoutUpdated - 窗口布局更改
- Loaded - 窗口现已布局,完全呈现
- ContentRendered - 所有窗口内容都已呈现
在应用程序关闭时,触发的 Window 事件(按顺序)是:
- Closing – 窗口即将关闭
- IsVisibleChanged – IsVisible 属性设置为 false
- Deactivated - 窗口成为背景窗口
- IsKeyboardFocusWithinChanged – IsKeyboardFocusWithin 属性设置为 false
- IsKeyboardFocusedChanged – IsKeyboardFocused 属性设置为 false
- LostKeyboardFocus - 窗口不再有键盘焦点
- Closed - 窗口正在关闭
42 – WPF 应用程序入口点
对于使用新建项目向导在 Visual Studio 2010 中生成的 WPF 独立应用程序,应用程序的入口点是 App.g.cs(生成的代码)中定义的 Main 函数。在默认项目中,这是 public static void App.Main 方法。
通常,.NET 应用程序将使用任何名为 Main 的具有公共/静态访问修饰符的方法作为其入口点(调用的第一个函数)——无论 Main 位于哪个类中。
如果您的应用程序有多个具有公共静态 Main 方法的类,则您需要在项目属性对话框中指定入口点。在 Startup object 下拉列表中,选择包含应在启动时调用的 Main 方法的类。
43 – WPF Main() 函数中发生了什么
使用 Visual Studio 2013 中的新建项目向导创建新的 WPF 独立应用程序时,Visual Studio 会自动创建一个派生自 System.Windows.Application 的类,以及一个静态 Main() 函数,该函数将成为第一个调用的函数应用程序启动。
以下是主应用程序对象的定义方式:
public partial class App : Application
在 Main 方法期间,应用程序通过以下方式启动:
- 创建 Application 对象的新实例 从 App.xaml
- 调用 Application.InitializeComponent 构成应用程序
- 调用 Application.Run 启动应用程序
public static void Main()
{
WpfApplication.App app = new WpfApplication.App();
app.InitializeComponent();
app.Run();
}
44 – 应用程序是单例
System.Application 类是一个单例,这意味着您最多可以创建一个 Application 实例(在单个 AppDomain 中)。如果您尝试创建 Application 的第二个实例,则会收到 InvalidOperationException。
可以通过静态属性 Application.Current 访问当前的 Application 对象。 (或使用派生类的属性,例如 App.Current)。
45 – 创建 WPF 控件的两种方法
使用 WPF 时,您始终可以通过以下两种基本方式之一创建控件:
- 在代码中以编程方式创建控件(例如 C#)
- 在 XAML 中以声明方式创建控件
例如,以下是为 WPF 应用程序创建主窗口的两种不同方法。
要在代码中创建主窗口,您需要为 Startup 事件添加应用程序对象的事件处理程序的代码。您通常会创建 window 对象,然后调用其 Show 方法。
private void Application_Startup(object sender, StartupEventArgs e)
{
MainWindow win = new MainWindow();
win.Show();
}
更常见的是,您可以通过为应用程序的 StartupUri 属性指定一个值,在 XAML 中指定应用程序的主窗口。对于新建项目向导创建的默认项目,您将在 App.xaml 中执行此操作:
<Application x:Class="WpfApplication.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
46 – 在 WPF 应用程序中处理命令行参数
可以通过读取应用程序启动事件的事件处理程序中的参数来处理传递给 WPF 应用程序的命令行参数。
命令行参数可以在 StartupEventArgs.Args 中找到。 Args 是一个字符串对象数组,其中包含在命令行中传入的参数。
private void Application_Startup(object sender, StartupEventArgs e)
{
foreach (string s in e.Args)
{
MessageBox.Show(string.Format("Arg: {0}", s));
}
}
也可以只覆盖 OnStartup 方法,而不是为 Startup 事件添加处理程序。
47 – 检测 Windows 会话何时结束
在 WPF 中,您可以通过处理 Application.SessionEnding 事件来检测用户何时结束其 Windows 会话。当用户退出 Windows 或关闭机器时会发生这种情况。
在您的事件处理程序中,您可以通过将 SessionEndingCancelEventArgs.Cancel 设置为 true 来取消 Windows 会话的终止。
private void Application_SessionEnding(object sender, SessionEndingCancelEventArgs e)
{
MessageBoxResult res = MessageBox.Show("Exiting Windows will terminate this app. Are you sure?", "End Session", MessageBoxButton.YesNo);
if (res == MessageBoxResult.No)
{
e.Cancel = true;
}
}
注意,此事件会在 Windows 退出时触发,但不会在应用程序以正常方式关闭时触发。
在 Windows 7 上,如果您的应用程序取消了关闭的 SessionEnding 事件,Windows 将通知用户您的应用程序正在阻止 Windows 关闭:
48 – 处理应用程序的退出事件
可以向 Application.Exit 事件处理程序添加代码,以执行需要在应用程序关闭/退出时执行的其他任务。
<Application x:Class="WpfApplication4.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
Exit="Application_Exit">
</Application>
private void Application_Exit(object sender, ExitEventArgs e)
{
// Perform tasks at application exit
}
当应用程序关闭或 Windows 会话结束时,会触发 Exit 事件。它在 SessionEnding 事件之后触发。您无法取消退出事件。
49 – 未处理的异常
如果在 WPF 应用程序中引发异常并且未在代码中的任何位置处理,则会发生未处理的异常并且应用程序将被强制退出。这将导致一个类似于以下的窗口:
发生这种情况时,应用程序会突然退出,用户没有机会保存任何未完成的工作,用户也无法获得其他信息。简而言之,应用程序崩溃。
可以通过处理 Application.DispatcherUnhandledException 事件来处理原本无法处理的异常。在下面的示例中,我们显示了更好的错误消息并设置了 Handled 属性,以避免关闭应用程序。
private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
string friendlyMsg = string.Format("SO sorry that something went wrong. The error was: [{0}]", e.Exception.Message);
string caption = "Error";
MessageBox.Show(friendlyMsg, caption, MessageBoxButton.OK, MessageBoxImage.Error);
// Signal that we handled things--prevents Application from exiting
e.Handled = true;
}
这会导致更好的错误:
50 – 应用范围的属性
Application 类包括一个名为 Properties 的属性,它是一个属性 IDictionary,存储为关键字/值对。您可以使用此字典来存储应具有应用程序范围的任何属性。
可以以线程安全的方式从任何线程读取或写入 Properties 字典中的属性值。
private void Application_Startup(object sender, StartupEventArgs e)
{
this.Properties.Add("Debug", false);
this.Properties.Add("Logger", null);
// Set properties based on command line parameters
foreach (string a in e.Args)
{
if (a.ToLower() == "/debug")
this.Properties["Debug"] = true;
else if (a.ToLower() == "/logging")
this.Properties["Logger"] = new MyAppLogger("Logfile.txt");
}
}
字典中的每个条目都是 System.Collections.DictionaryEntry 类型,因此它有一个 Key 属性(类型对象)和一个 Value 属性(类型对象)。这意味着您可以使用任何类型的对象作为键或值。您最常使用字符串作为键,使用各种对象作为值。