一个简单的例子就是大家在使用很多应用程序,例如在使用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. Filezilla出现中文乱码

    使用Filezilla client FTP客户端登陆某些FTP站点会出现中文乱码,原因是FTP服务器端编码与filezilla client端编码不一致造成的,解决方法如下:文件-站点管理-选中要登 ...

  2. redis来共享各个服务器的session,并同时通过redis来缓存一些常用的资源,加快用户获得请求资源的速度(转)

    时间过得真快,再次登录博客园来写博,才发现距离上次的写博时间已经过去了一个月了,虽然是因为自己找了实习,但这也说明自己对时间的掌控能力还是没那么的强,哈哈,看来还需不断的努力啊!(这里得特别说明一下本 ...

  3. JavaScript RegExp对象

    一.什么是RegExp         1.RegExp 是正則表達式的缩写. 2.当您检索某个文本时,能够使用一种模式来描写叙述要检索的内容.RegExp 就是这样的模式. 3.简单的模式能够是一个 ...

  4. 安装了VS2010 sp1 后再安装ASP.NET MVC 3.0的问题(Final Result: Installation failed with error code: (0x80070643), "安装时发生严重错误 " (Ela)

    原文:安装了VS2010 sp1 后再安装ASP.NET MVC 3.0的问题(Final Result: Installation failed with error code: (0x800706 ...

  5. Python数据结构-字典

    tel={,} tel[ print(tel) print(tel['tom']) del tel['tom'] print(tel) print(tel.keys()) 运行结果: {, , } { ...

  6. ORACLE 实验二

    实验二:数据操纵 实验学时:4学时 实验类型:综合型 实验要求:必修 一.实验目的 1.掌握SQL数据查询语句: 2.掌握SQL聚集函数的使用. 3.掌握SQL插入.改动.删除语句的使用. 二.实验内 ...

  7. Debian7.6安装过程中遇到的问题

    一 sudo命令不能用 1 使用su切换到root用户,命令: su 2 使用名:vim /etc/sudoers加入sudoer用户,命令: vim /etc/sudoers 找到root=(ALL ...

  8. RPC分布式处理

    RPC(远程过程调用)的应用 接触背景 因为工作上某项目的需要设计一种分布式处理耗时的运算,每个节点然后将运算结果返回给中心服务器,而最初未了解RPC这部分之前我的设计是在每一个RPC服务器上搭建一个 ...

  9. PHP 文件操作类(创建文件并写入) 生成日志

    <?php /** * 文件操作(生成日志)支持多条插入 * (假设插入多条语句并换行 用','逗号分开) * */ class log { public $path = './info.txt ...

  10. HDOJ 5276 YJC tricks time multimap

    multimap的使用 YJC tricks time Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 524288/262144 K ...