Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create single instance WPF Application that restores the open window when an attempt is made to open another instance? [duplicate]

Tags:

c#

wpf

Sorry it the title is hard to understand. I wasn't sure how to word it.

I have an application that should only be allowed to run one instance per user session. If the user clicks to launch the application again, I want to bring the one already to focus.

The window will likely have Visibility to collapsed.

If it's visible I know I can use

if (IsIconic(hWnd))
{
    ShowWindowAsync(hWnd, swRestore);
}

SetForegroundWindow(hWnd);

but if the window is collapsed, is there a way for me to bring it back to visible?

like image 760
Tsukasa Avatar asked Feb 14 '14 21:02

Tsukasa


People also ask

How do I make sure that only one instance of my application runs at a time?

The best way of accomplishing this is using a named mutex. Create the mutex using code such as: bool firstInstance; Mutex mutex = new Mutex(false, "Local\\" + someUniqueName, out firstInstance); // If firstInstance is now true, we're the first instance of the application; // otherwise another instance is running.

How do I run a single instance of the application using Windows Forms?

" This feature is already built in to Windows Forms. Just go to the project properties and click the "Single Instance Application" checkbox. "

How do I change the startup window in WPF?

If you look at App. xaml class of your WPF application, you will see the following XAML code. Here the StartupUri sets the startup Window of an application. If you want to change the Startup window to some other window, just change this value.


2 Answers

You're looking for the Mutex Class. It's pretty complicated, but luckily the Singleton Pattern has been widely discussed. There are several good articles on it, but you can find a good implementation of it in the C# .NET Single Instance Application page on the Sanity Free Coding website. From the linked page:

static class Program {
    static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
    [STAThread]
    static void Main() {
        if(mutex.WaitOne(TimeSpan.Zero, true)) {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
            mutex.ReleaseMutex();
        } else {
            MessageBox.Show("only one instance at a time");
        }
    }
}

Now you're probably wondering how to have a Main method in a WPF Application, right? Well there's a few things that you have to do, but it's not difficult. See the Writing a custom Main() method for WPF applications article which explains this in detail. From that article:

You basically need to change the application’s build action from “Application Definition” to “Page”, create a constructor that calls “InitializeComponent”, and write your Main() by eventually calling one of the application’s “Run” method overloads. ... Don’t forget, also, to remove the “StartupUri” from the App.xaml, otherwise another copy of window will show up (unless you get an error because the URI points to a non existing XAML resource).

So by amalgamating these two resources, we can see that your App.xaml.cs file should look something like this:

public partial class App : Application
{
    private static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
    private static MainWindow mainWindow = null;

    App()
    {
        InitializeComponent();
    }

    [STAThread]
    static void Main()
    {
        if(mutex.WaitOne(TimeSpan.Zero, true)) 
        {
            App app = new App();
            mainWindow = new MainWindow();
            app.Run(mainWindow);
            mutex.ReleaseMutex();
        }
        else
        {
            mainWindow.WindowState = WindowState.Normal;
        }
    }
}
like image 136
Sheridan Avatar answered Sep 18 '22 05:09

Sheridan


I removed the tag StartupUri from the App.xaml file.

Change the Build Action of App.xaml, from ApplicationDefinition to Page (You can change it on the property window).

Add a reference to Microsoft.VisualBasic (namespace to WindowsFormsApplicationBase).

On the class App.xaml.cs, put this code:

public partial class App : Application
{
    App()
    {
        InitializeComponent();
    }

    [STAThread]
    static void Main()
    {
        SingleInstanceManager manager = new SingleInstanceManager();
        manager.Run(new[] {"teste"});
    }
}

public class SingleInstanceManager : WindowsFormsApplicationBase
{
    SingleInstanceApplication app;

    public SingleInstanceManager()
    {
        this.IsSingleInstance = true;
    }

    protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e)
    {
        // First time app is launched
        app = new SingleInstanceApplication();
        app.Run();
        return false;
    }

    protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
    {
        // Subsequent launches
        base.OnStartupNextInstance(eventArgs);
        app.Activate();
    }
}

public class SingleInstanceApplication : Application
{
    protected override void OnStartup(System.Windows.StartupEventArgs e)
    {
        base.OnStartup(e);

        // Create and show the application's main window
        MainWindow window = new MainWindow();
        window.Show();
    }

    public void Activate()
    {
        // Reactivate application's main window

        this.MainWindow.WindowState = WindowState.Normal;
        this.MainWindow.Activate();
    }
}
like image 25
Ricardo França Avatar answered Sep 22 '22 05:09

Ricardo França