• WPF 10天修炼 第三天- Application全局应用程序类


    Application对象

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

    创建Application对象

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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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枚举值。

    1
    2
    3
    4
    5
    protected override void OnStartup(StartupEventArgs e)
    {
      base.OnStartup(e);
      this.ShutdownMode = ShutdownMode.OnMainWindowClose;
    }

     App.xaml中指定的ShutdownMode值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <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事件处理器。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <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 文件中添加下列事件处理器

    1
    2
    3
    4
    5
    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事件处理器的代码,使其启动时能够显示两个窗口。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //重载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);
      }
    1
    2
    3
    4
    5
    6
    //重载OnDeactivated事件,在窗体被取消激活时触发。
     protected override void OnDeactivated(EventArgs e)
     {
         base.OnDeactivated(e);
         System.Diagnostics.Debug.WriteLine("当前应用程序停止激活");
     }

    DispatherUnhandledException事件

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

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

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

    1
    2
    3
    4
    5
    6
    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事件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <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文件中添加如下代码  

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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文件中添加如下代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    /// <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事件中添加下列代码  

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    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();

     完整代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    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应用程序会弹出“已存在一个应用程序实例”对话框,并关闭当前应用程序。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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命名空间。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    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方法。  

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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、多次启动应用程序,发现同时只能运行一个实例。

    HK
  • 相关阅读:
    最全的 Twitter Bootstrap 开发资源清单
    jQuery布局插件UI Layout简介及使用方法
    SQLcode错误代码汇总和sqlstate=37000的解决方案
    JQUERY插件学习之jQuery UI
    如何判断/检查一个集合(List<string>)中是否有重复的元素
    反射原理及简介
    C# 获取文件夹下的所有文件的文件名
    委托编程指南
    模块封装与程序集
    Redis Lock
  • 原文地址:https://www.cnblogs.com/HarryK4952/p/14445301.html
Copyright © 2020-2023  润新知