There are many ways of making a WPF application a single instance application but such solutions are mostly difficult to find, or even if you manage to find one, they solve one problem and create another. Here are two ways of doing the same, and a solution created by me which is a hybrid of two posts I saw on the net.
1. Remove the App.xaml file completely
The first method is by removing the App.xaml completely which is perfectly demonstrated by this MSDN article.
2. Use Interop services
The second method is by using COM and Interop services which makes your application single instance with almost no code at all. This method was posted on this thread by Marco Zhou. A example is given below:
1: <cc:WpfApplication x:Class="SingleInstanceAppDemo.App"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:cc="clr-namespace:Sheva.Windows"
5: IsSingleInstance="True"
6: StartupUri="Window1.xaml">
7:
8: <cc:WpfApplication.Resources>
9: <Style TargetType="{x:Type TextBlock}">
10: <Setter Property="Foreground" Value="White"/>
11: <Setter Property="FontSize" Value="40"/>
12: <Setter Property="FontWeight" Value="Bold"/>
13: <Setter Property="FontFamily" Value="Verdana"/>
14: </Style>
15: </cc:WpfApplication.Resources>
16: </cc:WpfApplication>
17:
The source can be downloaded here.
3. Making application Single Instance without deleting App.xaml or using Interop
This is the way I pefer it but I tried to search the net but did not found any way of doing anything like that. Then I stumbled upon this post which shows you how to provide your own Main() method in a WPF application. As soon as I found this, I made a hybrid of this Main() method output and the MSDN article to successfully create a solution to the problem at hand.
All you have to do is, make the build action of App.xaml to ApplicationDefinition as mentioned in this post and write this in your App.cs:
1: using System;
2: using System.Collections.Generic;
3: using System.Configuration;
4: using System.Data;
5: using System.Linq;
6: using System.Windows;
7:
8: using Microsoft.VisualBasic.ApplicationServices;
9:
10: namespace YourNamespace
11: {
12: public class EntryPoint
13: {
14: [STAThread]
15: public static void Main(string[] args)
16: {
17: SingleInstanceManager manager = new SingleInstanceManager();
18:
19: manager.Run(args);
20: }
21: }
22:
23: // Using VB bits to detect single instances and process accordingly:
24: // * OnStartup is fired when the first instance loads
25: // * OnStartupNextInstance is fired when the application is re-run again
26: // NOTE: it is redirected to this instance thanks to IsSingleInstance
27: public class SingleInstanceManager : WindowsFormsApplicationBase
28: {
29: YourApplication app;
30:
31: public SingleInstanceManager()
32: {
33: this.IsSingleInstance = true;
34: }
35:
36: protected override bool OnStartup(
37: Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e)
38: {
39: // First time app is launched
40: app = new YourApplication();
41: // You have to add this line to the MSDN sample
42: // to make it work here...
43: app.InitializeComponent();
44: app.Run();
45:
46: return false;
47: }
48:
49: protected override void OnStartupNextInstance(
50: StartupNextInstanceEventArgs eventArgs)
51: {
52: // Subsequent launches
53: base.OnStartupNextInstance(eventArgs);
54: app.Activate();
55: }
56: }
57:
58: /// <summary>
59: /// Interaction logic for App.xaml
60: /// </summary>
61: public partial class YourApplication : Application
62: {
63: protected override void OnStartup(
64: System.Windows.StartupEventArgs e)
65: {
66: base.OnStartup(e);
67:
68: /* And remove this ...
69: // Create and show the application's main window
70: MainWindow window = new MainWindow();
71: */
72:
73: window.Show();
74: }
75:
76: public void Activate()
77: {
78: // Reactivate application's main window
79: this.MainWindow.Activate();
80: }
81: }
82: }
83:
Download the file here.
We use InitializeComponent in the OnStartup routine (line 43) to make the main window run and show immediately. As your App.xaml already contains this information as the StartupUri, InitializeComponent will itself determine which is the window you want. A good side effect of this approach is that you don't need to have the name of your main window defined explictly.
As the main window is already visible, we don't need to show the main window yet again in YourApplication.OnStartup, do we? If we do, we will have two copies of the main window running together.To avoid this, we have to comment line 69 and 70.
But this approach has a flaw. If you use this approach, every global resource you will define in the App.xaml will not show up in the designer windows of both Visual Studio 2008 and Expression Blend. Although the application will show up the resources just fine when ran. I am trying to find a workaround to this problem and will post it as soon as I find it.
I hope this helps everybody who is looking for such a hybrid solution.