最近有同事问道在应用程序启动之后,再次双击应用程序,如何保证不再启动新的应用程序,而是弹出之前已经启动的进程,本质上这就是创建一个单实例的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. Python 中 (&,|)和(and,or)之间的区别

    &,|)和(and,or)是两组比较相似的运算符,用在“与”/ “或”上,在用法上有些许区别. (&,|)和(and,or)是用来比较两组变量的,格式基本上是: a & ba ...

  2. 如何转换pdf文档为word文档--先标记下,本周把这个问题知识掌握

    http://developer.51cto.com/art/201803/567539.htm

  3. js 放在公共头部 子页面引用js 失效问题

    先回忆一下二者的区别(对于此篇文章而言,二者在用法上没有区别) jsp:include是先编译一下included.jsp文件,然后再包含 先编译,后包含 @ include是先把文件包含就来,然后统 ...

  4. 8-组成n的1的个数

    /*                                             ones时间限制:1000 ms  |  内存限制:65535 KB难度:3 描述    Given a ...

  5. VBA json parser[z]

    http://www.ediy.co.nz/vbjson-json-parser-library-in-vb6-xidc55680.html VB-JSON: A Visual Basic 6 (VB ...

  6. 函数中返回char *类型

    记录一次比较容易引起混淆的地方. #include <stdio.h> char *str(void) { return "nihao\n"; } int main() ...

  7. ldd "symbol lookup error"问题解决

    http://www.linuxquestions.org/questions/slackware-14/symbol-lookup-error-usr-lib-libgtk-x11-2-0-so-0 ...

  8. Android界面设计

    从继承关系来看,所有组件继承自View.容器也是继承自View,它能容纳别的View. 所有容器继承自ViewGroup.包括 FrameLayout, LinearLayout, RelativeL ...

  9. 13.8.8 div块 居中

    <div style="border:1px solid blue;width:760px; height:410px; position:absolute; left:50%; to ...

  10. 39 What Determines the Kind of Person You Are ?是什么决定了你是哪种内型的人 ?

    What Determines the Kind of Person You Are ?是什么决定了你是哪种内型的人 ? ①What determines the kind of person you ...