Application对象

  当一个WPF应用程序启动时,首先会实例化一个全局唯一的Application对象,类似于WinForm下的Application类,用于控制整个应用程序,该类将用于追踪应用程序打开的窗口。在应用程序打开或关闭的时候能够触发相应的事件。

创建Application对象

手动创建Application应用程序对象过程:

1、  使用VS创建WPF应用程序,命名为WPFDemo。然后手动清除App.xaml文件。

2、  添加Startup.cs类,并添加程序代码。如下:

using System.Windows;//添加windows命名空间

namespace WPFDemo
{
public class Startup
{
[STAThread]
public static void Main()
{
Application app = new Application();//创建application对象 MainWindow win = new MainWindow();//实例化窗口对象,作为应用程序主窗口 win.Title = "应用程序主窗口";//指定应用程序窗口标题 app.Run(win);//调用Run方法开始运行应用程序
}
}
}

3、  F5启动应用程序。

关闭应用程序

Application类提供了一个ShutdownMode的枚举属性值,可以供开发人员指定应用程序的关闭模式。开发人员可以在Application的OnStartup事件为这个属性赋值,也可以在XAML文件中设置这个属性。

ShutdownModel 枚举值

枚举值

说明

OnLastWindoClose

当最后一个窗口关闭或在调用Application.Shutdown方法时,应用程序将关闭。

OnMainWindowClose

主窗口关闭或者调用Application.Shutdow方法时,应用程序关闭。

OnExplicitShutdown

即使所有窗口都被关闭,应用程序也不会终止。这个方法适用于一些长时间运行后台任务的场合。当显式调用Application.Shutdown方法后,应用程序才会退出。

Application类OnStartup事件中设置ShutdownMode枚举值。

  protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
this.ShutdownMode = ShutdownMode.OnMainWindowClose;
}

App.xaml中指定的ShutdownMode值

<Application x:Class="WPFDemo.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFDemo"
StartupUri="MainWindow.xaml"
ShutdownMode="OnLastWindowClose">
<Application.Resources> </Application.Resources>
</Application>

应用程序事件

应用程序执行将会按照顺序触发下列事件。

1、  Startup:应用程序启动事件。

2、  Activated:当应用程序的顶层窗口被激活时触发此事件。

3、  Deactiveated:当应用程序的顶层窗口失去焦点时触发此事件。

4、  DispatherUnhandledException:当应用程序的产生未处理异常时触发此事件。

5、  SessionEnding:当Windows会话被终止时触发此事件,例如用户注销或关闭计算机。

6、  Exit:当应用程序因为某种原因而被关闭时触发此事件。

Startup 应用程序启动事件

该事件在Run方法被调用后触发,这个事件通常用于放置应用程序范围的初始化信息。获取和设置应用程序范围的配置,处理命令行参数等。该事件提供了StartupEventArgs类型的参数,包含了命令行参数信息。

Startup事件可以完成下列任务。

(1)、处理命令行参数。

(2)、打开主窗口。

(3)、初始化应用程序范围的资源。

(4)、初始化应用程序范围的属性。

Startup事件,首先在App.xaml文件中,去掉StartupUri属性,关联Startup事件处理器。

<Application x:Class="WPFDemo.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFDemo"
Startup="Application_Startup">
<Application.Resources> </Application.Resources>
</Application>

接下来在 App.xaml.cs 文件中添加下列事件处理器

private void Application_Startup(object sender, StartupEventArgs e)
{
  MainWindow win = new WPFDemo.MainWindow();
  win.Show();
}

在实际项目开发中,OnStartup中的代码可以非常复杂,可以读取应用程序资源或读取应用程序设置中读取配置信息,配置参数等。

Activated和Deactiveated事件

应用程序的激活与Window的激活和取消激活类似,但应用程序的激活通常是指全局应用程序的激活,通常发生在如下情况下:

1、  应用程序打开第一个窗口。

2、  用户使用Alt+Tab组合件或者使用任务管理器切换到该应用程序。

3、  用户单击应用程序中一个窗口的任务栏按钮。

与窗口不同的是,一旦应用程序激活,在应用程序停用前都不会再次引发Activated事件。

在上面示例中新增一个名为Window2.xaml的窗口。并修改OnStartup事件处理器的代码,使其启动时能够显示两个窗口。

    private void Application_Startup(object sender, StartupEventArgs e)
    {
    MainWindow win = new WPFDemo.MainWindow();
    win.Title = "通过OnStartup事件启动的主窗口";
    win.Show();     Window2 win2 = new Window2();
    win2.Title = "通过OnStartup时间启动的第二个窗口";
    win.Show();
    }
      //重载OnActivated事件,在窗体被激活时触发。
protected override void OnActivated(EventArgs e)
{
System.Diagnostics.Debug.Write("当前应用程序被激活");
foreach (Window win in Windows)
{
if (win.IsActive)
{
System.Diagnostics.Debug.WriteLine("当前的活动窗口是:" + win.Title);
}
}
base.OnActivated(e);
}
       //重载OnDeactivated事件,在窗体被取消激活时触发。
protected override void OnDeactivated(EventArgs e)
{
base.OnDeactivated(e);
System.Diagnostics.Debug.WriteLine("当前应用程序停止激活");
}

DispatherUnhandledException事件

DispatcherUnhandledException 给开发人员一个处理应用程序为处理的异常的地方。在window1.xaml.cs 的构造函数中抛出一个异常。

public Window1()
{
  InitializeComponent();
  throw new Exception("演示DispatherUnhandledException的作用,这里抛出一个异常");
}

然后在App.xaml中添加对DispatherUnhandledException属性的赋值,最后在App.xaml.cs中添加一些代码来显示一个自定义的错误窗口。

      private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
string err = "异常信息:" + e.Exception.Message.ToString();
MessageBox.Show(err);
e.Handled = true;
}

运行应用程序将会弹出下面对话框

SessionEnding事件 – 注销或关闭系统 

当Windows操作系统的会话终止时,则会触发SessionEnding事件。SessionEnding事件有一个SessionEndingCancelEventArgs类型的参数,该参数有一下Cancel布尔属性,当设置为true时,将会取消windows的会话终止行为。除此之外,还可以使用ReasonSessionEnding枚举类型的属性,来检测终止会话的类型,该属性有下面两个值:

1、  Logoff :会话正在结束的原因是用户正在注销。

2、  Shutdown : 会话正在结束的原因是用户正在关闭Windows。

下面演示如何使用SessionEnding事件,当windows应用程序终止时,弹出一个对话框窗口提示用户进行选择。

App.xaml 文件制定SessionEnding事件

<Application x:Class="WPFDemo.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFDemo"
Startup="Application_Startup"
SessionEnding="Application_SessionEnding"
>
<Application.Resources> </Application.Resources>
</Application>

在App.xaml.cs文件中添加如下代码

     private void Application_SessionEnding(object sender, SessionEndingCancelEventArgs e)
{
//询问用户是否允许终止会话
string msg = string.Format("{0} 是否要终止Windows会话?", e.ReasonSessionEnding);
MessageBoxResult result = MessageBox.Show(msg, "Session Ending", MessageBoxButton.YesNo);
if (result == MessageBoxResult.No)
{//如果点击yes,允许终止,否则禁止终止会话
e.Cancel = true;
}
}

运行应用程序,当windows终止会话时,应用程序会弹出如下图的对话框,如果用户点击“取消”按钮,则会取消终止Windows会话。

Exit事件

当应用程序退出时,将触发Exit事件。下面演示应用程序退出时,向用户隔离区写入应用程序日志和应用程序状态。首先在App.xaml代码中添加事件处理器声明

App.xaml文件

<Application x:Class="WPFDemo.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFDemo"
Startup="Application_Startup" DispatcherUnhandledException="Application_DispatcherUnhandledException" SessionEnding="Application_SessionEnding"
Exit="Application_Exit"
> <Application.Resources> </Application.Resources>
</Application>

在App.xaml.cs文件中添加如下代码

        /// <summary>
/// 应用程序退出标志
/// </summary>
public enum ApplicationExitCode
{
Success = 0,
Failure = 1,
CantWriteToApplicationLog = 2,
CantPersistApplicationState = 3
} /// <summary>
/// 应用程序退出
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Application_Exit(object sender, ExitEventArgs e)
{
try
{
if (e.ApplicationExitCode == (int)ApplicationExitCode.Success)
{
WriteApplicationLogEntry("Failure", e.ApplicationExitCode);
}
else
{
WriteApplicationLogEntry("Success", e.ApplicationExitCode);
}
}
catch
{
//写入应用程序失败时,更新退出代码已反映出写入失败
e.ApplicationExitCode = (int)ApplicationExitCode.CantWriteToApplicationLog; } //保存应用程序状态
try
{
PersistApplicationState();
}
catch
{
//写入应用程序失败时,更新退出代码已反映出写入失败
e.ApplicationExitCode = (int)ApplicationExitCode.CantPersistApplicationState;
}
}
/// <summary>
/// 记录应用程序日志
/// </summary>
/// <param name="message"></param>
/// <param name="exitCode"></param>
private void WriteApplicationLogEntry(string message, int exitCode)
{
//写入日志项到用户隔离存储区
IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForAssembly();
using (Stream stream = new IsolatedStorageFileStream("log.txt", FileMode.Append, FileAccess.Write, store))
{
using (StreamWriter writer = new StreamWriter(stream))
{
string entry = string.Format("{0}:{1} - {2}", message, exitCode, DateTime.Now);
writer.WriteLine(entry);
}
}
}
/// <summary>
/// 记录应用程序状态日志
/// </summary>
private void PersistApplicationState()
{
//保存应用程序状态到用户隔离存储区
IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForAssembly();
using (Stream stream = new IsolatedStorageFileStream("state.txt", FileMode.Create, store))
using (StreamWriter writer = new StreamWriter(stream))
{
//可以在这里更改为自定义的保存应用程序状态的程序代码
foreach (DictionaryEntry entry in this.Properties)
{
writer.WriteLine(entry.Value);
}
}
}

上面代码中,首先定义一个推出的枚举类型。在应用程序Exit事件触发,根据不同的推出写入不同的信息到用户的隔离存储区。通常在Exit事件中保存应用程序的配置信息,当应用程序启动时可以在Startup加载配置信息。

Application类的任务 

处理命令行参数

在WPF应用程序中,可以使用两种方法来处理命令行参数。一种是通过Environment对象的静态GetCommandLineArgs方法,另一种是通过相应Application类的Startup事件。该事件提供了SartupEventArgs类型的参数,该参数中包含了从命令行提示符或桌面传递的命令行参数。

使用Startup中 StartupEventArgs获取命令行参数

 在App.xaml中指定Startup=”Application_Startup”事件,并在App.xaml.cs Startup事件中添加下列代码

        private void Application_Startup(object sender, StartupEventArgs e)
{
//该bool值将从命令行参数中获取。如果制定了特定的命令行参数,则将该bool值设置为true;
bool startMinimized = false;
//命令行参数是一个字符串数组类型,遍历参数数组,寻找特定的命令行参数。 for (int i = 0; i < e.Args.Length; i++)
{
if (e.Args[i] == "/StartMinimized")
{
startMinimized = true;
}
} //创建应用程序主窗口,如果指定了命令行参数,则最小化运行应用程序。并在窗口显示第一个命令行参数。 Window1 win = new Window1(); if (startMinimized)
{
win.WindowState = WindowState.Minimized;
win.Content = "当前命令行参数" + e.Args[0];
}
win.Show();
}

下面在项目中设置命令行参数来调试应用程序。首先在项目名称点击【右键】选择【属性】【调试】然后再命令行参数设置/StartMinimized。(如下图)然后启动应用程序发现应用程序以最小化方式运行,并且在窗体中显示“当前命令行参数/StartMinimized”

也可以使用CMD命令加参数的方式启动应用程序(如下图):

1、  打开CMD命令窗口。

2、  使用cd命令进入应用程序所在的文件夹。 命令: cd 目录名称

3、  然后执行exe应用程序,并指定参数。命令:WPFDemo.exe /StartMinimized

使用Environment的GetCommandLineArgs方法获取命令行参数

 只需要将上面代码中获取参数部分替换为

string[] args = Environment.GetCommandLineArgs();

完整代码如下:

        private void Application_Startup(object sender, StartupEventArgs e)
{
//该bool值将从命令行参数中获取。如果制定了特定的命令行参数,则将该bool值设置为true; bool startMinimized = false; ///使用Environment的GetCommandLineArgs方法获取命令行参数
string[] args = Environment.GetCommandLineArgs(); //命令行参数是一个字符串数组类型,遍历参数数组,寻找特定的命令行参数。
foreach (string arge in args)
{
if (arge == "/StartMinimized")
{
startMinimized = true; }
}
//创建应用程序主窗口,如果指定了命令行参数,则最小化运行应用程序。并在窗口显示第一个命令行参数。 Window2 win = new Window2();
if (startMinimized)
{
win.WindowState = WindowState.Minimized;
win.Content = "当前命令行参数" + e.Args[0];
}
win.Show();
}

 

单实例应用程序

一个WPF应用程序可以被打开多次,并产生多个进程。在很多场景下只能允许运行一个应用程序。下面提供两种方式创建单实例的应用程序

1、  使用System.Threading命名空间中的Mutex,称为同步基元或者互斥元。

2、  使用windowsFormsApplicationBase类实现单实例应用程序。

使用System.Threading命名空间的Mutex创建单实例应用程序。

1、  引用System.Threading命名空间,定义Mutex对象。

2、  重载Startup方法

3、  运行两个WPF应用程序会弹出“已存在一个应用程序实例”对话框,并关闭当前应用程序。

       Mutex mutex;

        protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
string mutexName = "WPFDemo";
bool CreatedNew;
mutex = new Mutex(true, mutexName, out CreatedNew); if (!CreatedNew)//如果有存在的实例,则关闭当前实例
{
MessageBox.Show("已存在一个应用程序实例");
Shutdown();
}
}

使用windowsFormsApplicationBase实现单实例应用程序。 

1、  添加Microsoft.VisualBasic.dll程序集的引用。

2、  新建SingleApplicationBase类,并添加

  Microsoft.VisualBasic 和 Microsoft.VisualBasic.ApplicationServices命名空间。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text; //添加命名空间
using Microsoft.VisualBasic;
using Microsoft.VisualBasic.ApplicationServices; namespace SingleInstanceWithCommunication
{
public class SingleApplicationBase : WindowsFormsApplicationBase
{
public SingleApplicationBase()
{
this.IsSingleInstance = true; //设置为允许单例模式
} private App wpfApp; protected override bool OnStartup(StartupEventArgs eventArgs)
{
wpfApp = new App();
wpfApp.Run();
return false;
}
//当有其他应用程序实例化时,则出发此事件,将WPF应用程序中显示一个新的窗口
protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
{
base.OnStartupNextInstance(eventArgs);
Console.WriteLine("启动实例");
} }
}

3、  右键选择App.xaml页面的属性,更改生成操作位Page。

4、  然后再App.xaml.cs中添加代码。重载Onstartup事件,设置启动页面,然后创建应用程序启动的Main方法。

        protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow win = new SingleInstanceWithCommunication.MainWindow();
this.MainWindow = win;
win.Show();
} [STAThread]
public static void Main(string[] args)
{
SingleApplicationBase sab = new SingleApplicationBase();
sab.Run(args);
}

5、多次启动应用程序,发现同时只能运行一个实例。

WPF 10天修炼 第三天- Application全局应用程序类的更多相关文章

  1. Application全局应用程序类

    当一个WPF应用程序启动时,先会实例化一个全局的唯一的Application.如果开发人员熟悉Windows Form编程,会知道在SystemWindowsForm命名空间中有一个Applicati ...

  2. WPF 10天修炼 第八天 - 形状、画刷和变换

    图形 在WPF中使用绘图最简单的就是使用Shape类.Shape类继承自FrameworkElement,是一个专门用来绘图的类.Shape类中年派生的类有直线.矩形.多边形和圆形等. System. ...

  3. WPF 10天修炼 第一天- 入门

    简介 WPF技术基于DirectX,完美的整合了矢量图形.2D或3D绘图技术.文件及多媒体技术.WPF将开发人员和设计人员的职责清楚的分离,提供了一种声明编程语言XAML.同时Expression B ...

  4. WPF 10天修炼 第二天- XAML语言

    XAML是什么 XAML是一种与.NET CLR紧密集成的声明性UI标记语言.XAML中的对象元素对应到CLR中的类型或结构.XAML命名空间对应到CLR中类的命名空间,元素类型则对应到CLR中的类型 ...

  5. Thinkphp源码分析系列(三)– App应用程序类

    // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO ...

  6. WPF 10天修炼 第十天- WPF数据绑定

    WPF数据绑定 数据绑定到元素属性是将源对象指定为一个WPF元素,并且源属性是一个依赖属性,依赖属性内置了变更通知.当改变源对象依赖属性值之后,绑定目标可以立即得到更新,开发人员不需要手动编写响应事件 ...

  7. WPF 10天修炼 第七天- WPF资源、样式、控件模板

    WPF资源 对象资源 WPF允许在XAML标记的任意位置定义资源.比如在特定的控件.窗口或应用程序级别定义资源,WPF资源系统提供的对象资源有如下好处: 1.  高效:使用对象资源可以在一个地方定义而 ...

  8. WPF 10天修炼 第四天- WPF布局容器

    WPF布局 WPF的窗口也就是Window类,是一个内容控件,该控件派生自ContentControl.内容控件有一个Content属性,该属性有一个限制,只能放置一个用户界面元素,或一个字符串.为了 ...

  9. WPF 10天修炼 第九天 - 几何图形

    几何图形 使用LineGeometry.RectangleGeometry.EllipseGeometry对象分别绘制直线.矩形.椭圆. 使用GeometryGroup可以绘制组合图形. <Wi ...

随机推荐

  1. MySQL之执行流程

    最近开始在学习mysql相关知识,自己根据学到的知识点,根据自己的理解整理分享出来,本篇文章会分析下一个sql语句在mysql中的执行流程,包括sql的查询在mysql内部会怎么流转,sql语句的更新 ...

  2. 基于Python玩转人工智能最火框架 TensorFlow应用实践

    慕K网-299元-基于Python玩转人工智能最火框架 TensorFlow应用实践 需要联系我,QQ:1844912514

  3. LODOP中tfoot和tbody中间线连不起来

    这种情况发生在使用ADD_PRINT_TABLE时,ADD_PRINT_TABLE是Lodop中专门用来输出table表格的语句,它有很多特点,比如该语句不切行(详细可参考查看本博客相关博文:LODO ...

  4. Java 学习体系结构

    一. JavaWEB 阶段课程体系结构 java se基础学习 二 .JavaWEB 阶段课程体系结构 第一阶段:前端开发阶段 1 HTML   2 CSS JS    3JS    4 JQuery ...

  5. java 中的引用数据类型

    字符串String 在java 中,字符串不是基本数据类型,而是String 类的对象,当我们创建一个字符串的时候,真的是要使用new 来调用String 构造函数 String str = new ...

  6. 关于Vue修改默认的build文件存放的dist路径

    原文地址:http://www.cnblogs.com/JimmyBright/p/7681086.html Vue默认build路径是项目的dist目录下,有时候我们可能希望build之后的文件自动 ...

  7. LeetCode--689_Maximum_Sum_of_3_NonOverlapping_Subarrays

    原题链接:点击这里 一道很水很水的背包问题? 大概算不上背包吧QAQ 自己的dp 真的是太差劲啦,以后每天一道LeetCode 备战秋招! package leetcode; public class ...

  8. Java 8 特性 —— lambda 表达式

    Lambda 表达式 Lambda表达式本质上是一个匿名方法.常见的一个例子是,在 IDEA + JDK8 的环境下按照Java传统的语法规则编写一个线程: new Thread(new Runnab ...

  9. (二叉树 递归) leetcode 889. Construct Binary Tree from Preorder and Postorder Traversal

    Return any binary tree that matches the given preorder and postorder traversals. Values in the trave ...

  10. Pushgateway 介绍

    Pushgateway是一个独立的服务,Pushgateway位于应用程序发送指标和Prometheus服务器之间. Pushgateway接收指标,然后将其作为目标被Prometheus服务器拉取. ...