最近有同事问道在应用程序启动之后,再次双击应用程序,如何保证不再启动新的应用程序,而是弹出之前已经启动的进程,本质上这就是创建一个单实例的WPF应用程序。在VS的工程树中有一个App.xaml和App.xaml.cs(这两个文件都是VS自动生成的),在App.xaml.cs中定义了App类,该类继承自System.Windows.Application,从类的命名上也很容易看出这些类是跟应用程序的管理相关的,在讲创建单实例应用程序之前,我们先了解一下Application这个类。

在上一篇WPF点滴(1) Main 函数中有部分对Application类的介绍,Application类封装了WPF应用程序,并管理其生命周期,以下代码用来创建一个Application:

Application app = new Application();
TestWindow window = new TestWindow();
app.MainWindow = window;
window.Show();
app.Run();

上面的代码创建了一个Application,并将该Application的主窗口设置为TestWindow,可以将以上代码简化为同样作用的以下代码:

Application app = new Application();
TestWindow window = new TestWindow();
app.Run(window);

需要注意的是VS自动生成的App类中使用了另一种方法来初始化Application和主窗口,通过资源路径来设置主窗口,

Application app = new Application();
app.StartupUri = new Uri("TestWindow.xaml", UriKind.Relative);
app.Run();

以上介绍了如何通过代码启动一个WPF应用程序,下面介绍以下Application类的几个常用场景:

1. 应用程序启动后的初始化和退出前的清理,这里会用到Startup和Exit这两个事件,或者重载OnStartup和OnExit,这两种方法是等效的,分别在程序启动和退出时触发;

2. 捕获应用程序未处理的异常,DispatcherUnhandledException,异常处理的原则是就近捕获,就近处理,这个事件更多是为了处理意料外的异常,防止程序奔溃的最后一层保护,因此不推荐过分依赖于这个事件中的异常处理。另外需要注意的是这个事件只会捕获主线程(UI线程)中的异常,后台线程中的未处理异常不会触发该事件;

3. 在后台线程中访问UI,Application.Current.Dispatcher.Invoke(),这种方法比较简单,另外一种方式是通过SynchronizationContext,这种方式更灵活一些。

现在终于可以切入正题了,如何创建创建单实例应用程序,前面说到了Startup这个事件,比较直接的方法是Startup的事件处理函数里判断是否已经存在了另外一个已经启动的应用程序,如果是就结束当前程序。这种方法可以实现单实例应用程序的效果,但是太暴力了,而且严格意义上并不是完全的单实例,应用程序毕竟已经启动了,虽然又被干掉了。

下面介绍的是WPF的推荐方式,使用Windows窗体提供的内置支持,借助WindowsFormsApplicationBase类,指定应用程序为单实例模式“IsSingleInstance = true”,

public class SingleInstanceApplication : WindowsFormsApplicationBase
{
  private App m_App;

  public SingleInstanceApplication()
  {
    IsSingleInstance = true;
  }

  protected override bool OnStartup(StartupEventArgs eventArgs)
  {
    m_App = new App
    {
      StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative)
    };
    m_App.Run();

    return false;
  }

  protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
  {
    base.OnStartupNextInstance(eventArgs);
  }
}

重写Main函数(具体方法参见WPF点滴(1) Main 函数),可以看到SingleInstanceApplication充当了App的wrapper,通过SingleInstanceApplication来启动应用程序,并做单实例的的控制,SingleInstanceApplication.OnStartup()在应用程序首次启动时触发,SingleInstanceApplication.OnStartupNextInstance()在应用程序已经启动并尝试再次启动时触发。做这样的设计是为了实现类似Word这样的效果,Word只存在一个运行中的应用程序,每次双击并没有启动新的Word程序,只是打开了一个新窗口而已,而文档的路径就是通过“StartupEventArgs eventArgs”和“StartupNextInstanceEventArgs eventArgs”这两个命令行参数来传递的。

public class StartUp
{
  [STAThread]
  public static void Main(string[] args)
  {
    SingleInstanceApplication application = new SingleInstanceApplication();
    application.Run(args);
  }
}

WPF没有原生支持单实例模式,以上方法实际上是来自VB的一个设计特性,WindowsFormsApplicationBase的命名空间是Microsoft.VisualBasic.ApplicationServices,使用这个类需要添加对Microsoft.VisualBasic.dll的引用。

WPF点滴(2) 创建单实例应用程序的更多相关文章

  1. 使用 WPF 创建单实例应用程序

    一个简单的例子就是大家在使用很多应用程序,例如在使用Microsoft Word 时会遇到一种情况,不管你打开多少个文档,系统一次只能加载一个winword.exe 实例.当打开新文档时,文档在新窗口 ...

  2. WPF使用Mutex创建单实例程序失效

    vs2019 1.引入名称空间 using System.Threading; using System.Runtime.InteropServices; 2.导入dll并声明方法 [DllImpor ...

  3. WPF学习笔记 - 如何用WPF创建单实例应用程序

    使用一个已命名的(操作系统范围的)互斥量. bool mutexIsNew; using(System.Threading.Mutex m = new System.Threading.Mulex(t ...

  4. WPF 单实例应用程序

    例如:Microsoft Word,不管打开多少个文档(也不管它们是如何打开的),一次只能加载 winword.exe 一个实例. 这便是单实例应用程序. 对于这种单实例应用程序,WPF 本身并未提供 ...

  5. WPF:如何实现单实例的应用程序(Single Instance)

    原文:WPF:如何实现单实例的应用程序(Single Instance) 好吧,这是我将WPF与Windows Forms进行比较的系列文章的第四篇,讨论一下如何实现单实例(single instan ...

  6. Oracle - 给rac创建单实例dg,并做主从切换

    一.概述 本文将介绍如何给rac搭建单节点的dg,以及如何对其进行角色转换.预先具备的知识(rac搭建,单实例-单实例dg搭建) 二.实验环境介绍 主库rac(已安装rac,并已有数据库orcl)ra ...

  7. 关于struts和Spring 结合到一起之后存在ACtion创建单实例还是多

    struts 2的Action是多实例的并非单例,也就是每次请求产生一个Action的对象.原因是:struts 2的Action中包含数据,例如你在页面填写的数据就会包含在Action的成员变量里面 ...

  8. C# 实现单实例程序

    在我们经常使用的软件中,当我们已经打开后,再次打开时,有的软件不会出现两个.例如有道词典,会将上次的界面显示出来,或者提示我们“该程序已经运行...”.我通过一个简单的C# WPF例子来说明. 首先我 ...

  9. DevExpress Winform使用单例运行程序方法和非DevExpress使用Mutex实现程序单实例运行且运行则激活窗体的方法

    原文:DevExpress Winform使用单例运行程序方法和非DevExpress使用Mutex实现程序单实例运行且运行则激活窗体的方法 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA ...

随机推荐

  1. swift iOS开发初步使用

    使用Xcode6-Beta 创建一个swift空的工程,新建一个UIViewController,语言选择swift. 在MainViewController.swift 添加如下代码,声明变量及cl ...

  2. struts框架值栈问题二之值栈的内部结构

    2. 问题二 : 值栈的内部结构 ? * 值栈由两部分组成 > root -- Struts把动作和相关对象压入 ObjectStack 中--List > context -- Stru ...

  3. Spring官方文档翻译(1~6章)

    Spring官方文档翻译(1~6章) 转载至 http://blog.csdn.net/tangtong1/article/details/51326887 Spring官方文档.参考中文文档 一.S ...

  4. 删除pdf文件所有超链接

    最近在读deep learning 书Bengio那本,在Github上面下载的,下载回来全都是超链接, 超级烦,比如点一下梯度下降法,就直接跳转到数后尾的index. 我看书还喜欢老点,所以要把他们 ...

  5. sqlldr 笔记

    表结构 CREATE table sqlloader_test ( f1 char(20), f2 char(20), f3 number(16), f4 date ); 数据文件data.csv 1 ...

  6. 创建DB2数据库联合对象

    db2 1.db2 =>update dbm cfg using Federated YES 2. db2 =>db2stop force3. db2 =>db2start 4.创建 ...

  7. 【Mac】使用PicGIF制作gif动态图片

    动态图片是我们常常需要的,mac系统下制作gif图片,可以使用PicGIF,AppStore中有一个简单版本免费的 环境与工具 1.mac系统 2.PicGIF Lite(可以在AppStore下载) ...

  8. 非常实用的windows运行打开服务命令

    1.注册表-->regedit.exe 2.本地服务设置-->services.msc 3.远程桌面连接-->mstsc 4.检查windows版本-->winver 5.组策 ...

  9. docker镜像基本操作

    操作镜像 使用 docker 命令行操作 docker 镜像 获取镜像 使用「docker pull +镜像名称」从网络上下载image镜像 core@localhost ~ $ docker pul ...

  10. web.xml 404 500 配置

    web.xml <error-page> <error-code>404</error-code> <location>/error404.html&l ...