最近有同事問道在應用程序啓動以後,再次雙擊應用程序,如何保證再也不啓動新的應用程序,而是彈出以前已經啓動的進程,本質上這就是建立一個單實例的WPF應用程序。在VS的工程樹中有一個App.xaml和App.xaml.cs(這兩個文件都是VS自動生成的),在App.xaml.cs中定義了App類,該類繼承自System.Windows.Application,從類的命名上也很容易看出這些類是跟應用程序的管理相關的,在講建立單實例應用程序以前,咱們先了解一下Application這個類。html
在上一篇WPF點滴(1) Main 函數中有部分對Application類的介紹,Application類封裝了WPF應用程序,並管理其生命週期,如下代碼用來建立一個Application:app
Application app = new Application();
TestWindow window = new TestWindow();
app.MainWindow = window;
window.Show();
app.Run();ide
上面的代碼建立了一個Application,並將該Application的主窗口設置爲TestWindow,能夠將以上代碼簡化爲一樣做用的如下代碼:函數
Application app = new Application();
TestWindow window = new TestWindow();
app.Run(window);spa
須要注意的是VS自動生成的App類中使用了另外一種方法來初始化Application和主窗口,經過資源路徑來設置主窗口,命令行
Application app = new Application();
app.StartupUri = new Uri("TestWindow.xaml", UriKind.Relative);
app.Run();線程
以上介紹瞭如何經過代碼啓動一個WPF應用程序,下面介紹如下Application類的幾個經常使用場景:設計
1. 應用程序啓動後的初始化和退出前的清理,這裏會用到Startup和Exit這兩個事件,或者重載OnStartup和OnExit,這兩種方法是等效的,分別在程序啓動和退出時觸發;orm
2. 捕獲應用程序未處理的異常,DispatcherUnhandledException,異常處理的原則是就近捕獲,就近處理,這個事件更可能是爲了處理意料外的異常,防止程序奔潰的最後一層保護,所以不推薦過度依賴於這個事件中的異常處理。另外須要注意的是這個事件只會捕獲主線程(UI線程)中的異常,後臺線程中的未處理異常不會觸發該事件;htm
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的引用。