12.2 Application类的任务
本节将介绍使用Application类时可以实现的几种功能,比如访问命令行参数,获取当前应用程序类的实例,以及一个常见的单窗口应用程序示例。
12.2.1 处理命令行参数
在WPF中,可以使应两种方法来处理命令行参数,一种是使用Environment对象的静态GetCommandLineArgs方法,另外一种则是响应Application类的Startup事件,该事件提供了StartupEventArgs 类型的参数,该参数中包含了从命令提示符或者是桌面传递到应用程序的命令行参数。
下面新建一个名为HandleCommandLineDemo的WPF应用程序项目,在App.xaml中添加对Startup事件的事件处理器,并去掉StartupUri属性,应用程序的主窗口将在Startup事件处理器中创建,App.xaml代码如下所示:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="Application_Startup">
<Application.Resources>
<!--资源区-->
</Application.Resources>
</Application>
在Application_Startup区,将检测特定的命令行参数是否存在,如果存在的话,则最小化应用程序的主窗口,App.xaml.cs的代码如下所示:
该程序首先遍历StartupEventArgs类型的参数e中的Args属性,Args属性包含了命令行参数的一个字符串数组,通过判断是否存在/StartMinimized命令行参数,来设置布尔变量startMinimized。startMinimized将被主窗口用作窗口状态的条件,如果为True,则启动时最小化主窗口,否则以标准模式启动。当StartMinimized为True,本程序将会在窗口内容区显示当前的第一个命令行参数。
要调试此应用程序,首先进入项目属性窗口,选择调试项,在“启动选项|命令行参数”中输入命令行文本,如图12.7所示。
图12.7 设置命令行参数
现在按F5键运行应用程序,如果指定了命令行参数,则启动时主窗口会最小化,并在窗口中显示当前命令行参数的值,如果未指定命令行参数,则用标准模式启动。
12.2.2 访问当前的应用程序
位于PresentationFramework.dll中的Application类是一个单件类,开发人员可以在应用程序的任何位置使用Application.Current属性来访问Application类的实例。
Application对象提供了几个相当有用的属性,比如MainWindow,开发人员可以访问这个属性来获取应用程序的主窗口,Windows集合属性用于获取当前打开的应用程序窗口的集合。Properties属性可以访问和设置应用程序的设置,Resources属性可以访问和设置应用程序的资源。
下面创建一个新的项目,名为AccessingCurrentApplication,演示一下如何使用Menu控件来显示当前打开的多个窗口,该示例将使用Application.Windows集合属性来遍历当前打开的窗口文件,并添加到菜单项中,当用户点击菜单项中的窗口标题时,则激活其相应的窗口,本示例的创建步骤如下所示:
(1)创建一个新的WPF应用程序项目,命名为AccessingCurrentApplication,在VS项目模板生成的Window1.xaml文件中,添加一个Menu,代码如下所示:
<Window x:Class="AccessingCurrentApplication.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
Activated="MainWindow_Activated">
<!--StackPanel是一种堆叠面板,默认情况下,控件将垂直方向一个跟着一个排列显示-->
<StackPanel>
<!--添加Menu控件,并指定Menu菜单项-->
<Menu>
<MenuItem Header="文件">
<MenuItem Name="newWindowMenuItem" Click="newWindowMenuItem_Click" Header="新建窗口"></MenuItem>
<Separator></Separator>
<MenuItem Name="exitMenuItem" Click="exitMenuItem_Click" Header="退出"></MenuItem>
</MenuItem>
<!--当窗体激活时,将使用程序代码为其动态添加菜单项,添加窗体的标题-->
<MenuItem Name="windowMenuItem" Header="窗口">
</MenuItem>
</Menu>
</StackPanel>
</Window>
在该XAML文件中,首先为窗体添加了一个Activated事件处理器,目的在于每当主窗口被激活时,都会遍历当前应用程序中所有打开的窗口,并添加到windowMenuItem菜单项中,作为其子菜单。
(2)在Window1.xaml.cs程序代码中添加如下事件处理代码:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace AccessingCurrentApplication
{
/// <summary>
/// Window1.xaml 的交互逻辑
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
//添加一个当前窗口计数器
private int newWindowCount=0;
//当主窗口激活时,向windowMenuItem的子菜单添加菜单项,每个菜单项显示窗口的标题
void MainWindow_Activated(object sender, EventArgs e)
{
this.windowMenuItem.Items.Clear();
int windowCount = 0;
//这里使用Application.Current.Windows属性
foreach (Window window in Application.Current.Windows)
{
++windowCount;
MenuItem menuItem = new MenuItem();
menuItem.Tag = window;
menuItem.Header = window.Title;
menuItem.Click += new RoutedEventHandler(menuItem_Click);
this.windowMenuItem.Items.Add(menuItem);
}
}
//当单击菜单项时,激活窗口
void menuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem menuItem = (MenuItem)sender;
((Window)menuItem.Tag).Activate();
}
//当单击新建按钮时,创建一个新的窗口,并设置当前窗口内容为窗口标题
private void newWindowMenuItem_Click(object sender, RoutedEventArgs e)
{
Window win1 = new Window();
win1.Height = 300;
win1.Width = 300;
++newWindowCount;
win1.Content=win1.Title = "这是第" + newWindowCount.ToString().PadLeft(2, '0') + "个子窗口";
win1.Show();
}
//当单击退出按钮时,直接关闭主窗口,这里必须在App.xaml中设置ShutdownMode为OnMainWindowClose。
private void exitMenuItem_Click(object sender, RoutedEventArgs e)
{
Application.Current.MainWindow.Close();
}
}
}
这段代码完成的任务如下:
(1)当应用程序的主窗口激活时,遍历Application.Current.Windows属性,将每个窗口的标题作为MenuItem的Header属性,添加到windowMenuItem中。
注意:Tag是FrameworkElement类定义的一个Object类型的属性,可以在该属性中存储任何对象。
(2)当用户单击窗口菜单项下的子菜单时,将获取MenuItem对象的Tag属性值,强制转换为Window类,并调用其Activate方法来激活窗口。
(3)当用户单击新建窗口时,将会创建一个新的窗口,并将窗口计时器加1,然后将窗口的内容和标题设置为相同的值。
(4)当用户单击退出菜单项时,将直接关闭主窗口,为了使主窗口退出时能够关闭应用程序,本示例项目在App.xaml中将ShutdownMode设置为OnMainWindowClose,App.xaml代码如下所示:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
ShutdownMode="OnMainWindowClose">
<Application.Resources>
</Application.Resources>
</Application>
程序的运行效果如图12.8所示。
图12.8 使用应用程序类示例
12.2.3 单实例应用程序
单实例应用程序是指同一时刻只会有一个应用程序实例执行的应用程序,比如Microsoft Word,无论打开多少个文档,在进程中也只会看到一个WINWORD.EXE的进程,这个进程将控制所有己经打开的Word文档。默认情况下,一个WPF应用程序可以被打开多次,并产生多个进程,为了创建单实例应用程序,需要在Application类中编写一些代码。