一个简单的例子就是大家在使用很多应用程序,例如在使用Microsoft Word 时会遇到一种情况,不管你打开多少个文档,系统一次只能加载一个winword.exe 实例。当打开新文档时,文档在新窗口显示,但是始终只有一个应用程序控制所有文档窗口;如:可以提供平铺当前所有文档中相邻窗口的文档的特性。

  对于创建单实例的应用程序,WPF本身没有提供自带的解决方法,但可以通过变通的方式来实现——思路是当触发ApplicationStartup事件时,检查另一个实例是否在运行。方法是通过使用全局的mutex对像(mutex是操做系统中提供的用于进程间通信的同步方法)。虽然简单,但功能有限,如新实例无法与已经存在的实例进行通信。尤其是对于基于文档的用于程序而言,这确实是一个问题,如果新实例需要告诉已经存在的实例打开一个新的文档或者该文档是通过命令行参数传递的情况,那该使用什么方法来解决问题呢??

  WPF团队推荐我们一种最简单的方法就是:使用Windows  窗体提供的内置支持,该内置支持最初是用于VisualBasic 应用程序的,使用Window窗体和VisualBasic 的这一特新来开发基于C#的WPF程序会存在一个新旧应用程序之分,本质上旧式应用程序充当了WPF应用程序的封装器。流程是:当启动程序时将创建旧式应用程序,旧式应用程序接着创建WPF应用程序,旧式应用程序处理实例管理,而WPF应用程序处理正真的应用。

  下面我们通过一个实例来演示创建单实例应用程序的具体步骤:

一.创建WPF窗体项目,并添加Microsoft.VisualBasic.dll 引用。

二.首先创建一个Document.xaml,和 DocumentList.xaml 窗口文件,使用定义的类DocumentReference 表示对Document引用。

DocumentReference :

 public class DocumentReference
{
private Document document;
public Document Document
{
get { return document; }
set { document = value; }
} private string name;
public string Name
{
get { return name; }
set { name = value; }
} public DocumentReference(Document document, string name)
{
Document = document;
Name = name;
}
}

Document.LoadFile() 通过文件名读取文档内容,Document.OnClosed() 事件在文档窗体关闭时触发,用于从动态集合移除实例。

 public partial class Document : Window
{
private DocumentReference docRef; public Document()
{
InitializeComponent();
} public void LoadFile(DocumentReference docRef)
{
this.docRef = docRef;
this.Content = File.ReadAllText(docRef.Name);
this.Title = docRef.Name;
} protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
((WpfApp)Application.Current).Documents.Remove(docRef);
} }

DocumentList 窗体放置一个 <ListBox Name="lstDocuments"></ListBox> 的 lstDocuments控件,用于显示当前文档列表。

 public partial class DocumentList : Window
{
public DocumentList()
{
InitializeComponent(); lstDocuments.DisplayMemberPath = "Name";
lstDocuments.ItemsSource = ((WpfApp)Application.Current).Documents;
}
}

三.接着创建一个自定义的WPF类WpfApp.cs,该类继承于Windows.Application。在这里每当通过命令行参数传递给SingleInstanceApplication 类文件名时,会触发 SingleInstanceApplication 类的 OnStartupNextInstance 方法,并调用自定义的 ShowDocument() 方法为指定的文档加载文档窗体。

WpfApp:

  public class WpfApp : Application
{
private ObservableCollection<DocumentReference> documents =
new ObservableCollection<DocumentReference>();
public ObservableCollection<DocumentReference> Documents
{
get { return documents; }
set { documents = value; }
} protected override void OnStartup(System.Windows.StartupEventArgs e)
{
base.OnStartup(e);
//WpfApp.Current = this; DocumentList list = new DocumentList();
this.MainWindow = list;
list.Show(); // Load the document that was specified as an argument.
if (e.Args.Length > ) ShowDocument(e.Args[]); } public void ShowDocument(string fileName)
{
try
{
Document doc = new Document();
DocumentReference docRef = new DocumentReference(doc, fileName);
doc.LoadFile(docRef);
doc.Owner = this.MainWindow;
doc.Show();
doc.Activate();
Documents.Add(docRef);
}
catch
{
MessageBox.Show("Could not load document.");
}
}
}

  四.创建继承于WindowsFormsApplicationBase 的自定义类 SingleInstanceApplication.cs 该类将提供3个用于管理实例的重要成员。

  • IsSingleInstance 用于确定此应用程序是否为单实例应用程序,在构造函数中设置值为true。
  • 重写 OnStartup(),程序启动时,重写该方法并创建WPF应用程序对象。
  • 重写 OnStartupNextInstance(),当另一个应用程序启动时触发该方法,该方法提供了访问命令行的参数的功能。此时可以调用WPF应用程序类的方法来创建窗口,但不能创建另一个应用程序对象。

SingleInstanceApplication:

 public class SingleInstanceApplication : WindowsFormsApplicationBase
{
private WpfApp App;
public SingleInstanceApplication()
{
this.IsSingleInstance = true;
} protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs eventArgs)
{
string extension = ".testDoc";
string title = "SingleInstanceApplication";
string extensionDescription = "A Test Document"; //return base.OnStartup(eventArgs);
App = new WpfApp();
App.Run();
return false;
} protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
{
//base.OnStartupNextInstance(eventArgs);
if (eventArgs.CommandLine.Count > )
App.ShowDocument(eventArgs.CommandLine[]);
}
}

五. 由于应用程序需要在APP类之前就要创建SingleInstanceApplication 类,所以这里就需要同过传统的Main方法作为启动入口。

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

 六,为了测试单例程序,需要使用Window文件扩展名与程序相关联,将其文件类型注册。运行结果如下:

使用 WPF 创建单实例应用程序的更多相关文章

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

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

  2. WPF点滴(2) 创建单实例应用程序

    最近有同事问道在应用程序启动之后,再次双击应用程序,如何保证不再启动新的应用程序,而是弹出之前已经启动的进程,本质上这就是创建一个单实例的WPF应用程序.在VS的工程树中有一个App.xaml和App ...

  3. WPF 单实例应用程序

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

  4. [WPF]WPF设置单实例启动

    WPF设置单实例启动 使用Mutex设置单实例启动 using System; using System.Threading; using System.Windows; namespace Test ...

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

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

  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. asp.net出现正在中止线程解决方案

    刚才又再次遇到了一个之前遇到的问题,在这里记录一下. 起因: 如果使用 Response.End.Response.Redirect 或 Server.Transfer 方法,将出现 ThreadAb ...

  2. tera term 残ALT债券

    Setup -> Keyboard对话框 Meta key变: left 版权声明:本文博客原创文章,博客,未经同意,不得转载.

  3. SE 2014 年4月21日(一)

    如图配置 网络中存在四个自治系统,设备之间要求建立BGP对等体关系,发布BGP路由,使得全网BGP路由相互通讯. 要求 1. 由于AS 200中的路由信息频繁抖动,所以AS 100 和 AS 300 ...

  4. 第一个Python程序的Hello Python,竟然有问题

    print 'hello python' 运行时显示:SyntaxError: invalid syntax 解决办法: 这应该是版本的问题,Python2的话直接就可以输出,但是到了Python3需 ...

  5. POJ1470 Closest Common Ancestors 【Tarjan的LCA】

    非常裸的模版题,只是Tarjan要好好多拿出来玩味几次 非常有点巧妙呢,tarjan,大概就是当前结点和它儿子结点的羁绊 WA了俩小时,,,原因是,这个题是多数据的(还没告诉你T,用scanf!=EO ...

  6. TP 控制器扩展_initialize方法实现原理

    参考网址:http://gongwen.sinaapp.com/article-59.html 控制器扩展接口 系统Action类提供了一个初始化方法_initialize接口,可以用于扩展需要,_i ...

  7. 流动python - 一个极简主义event制

    event至少该系统的核心,以满足: 1.存储容器事件,可以被添加到事件来删除 2.触发事件fire 守则. class Event(list): def __call__(self, *args, ...

  8. MYSQL中的字符串连接符

    update `table` set nsdf = concat('a','b') where id=137

  9. Windows phone 8 学习笔记(5) 图块与通知

    原文:Windows phone 8 学习笔记(5) 图块与通知 基于metro风格的Windows phone 8 应用提到了图块的概念,它就是指启动菜单中的快速启动图标.一般一个应用必须有一个默认 ...

  10. TestThreadPoolExecutor.java

    package           ; import java.io.IOException;import java.io.InputStream;import java.util.List;impo ...