1

How can i achieve only 1 instance of my WPF application to run and open the window on the task bar? I know there are a lot of question about this topic on the web, but none of them has a clear answer(or at least any answer has worked for me on WPF) of how to do it. I programed the answer gave on this question, here is my code:

private static Mutex mutex = new Mutex(true, "{1111werqwfwf}");
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;
    }
}

The problem is that my MainWindow is not opened. Also, i need to open the PointOfSale window which was the one minimized to the task bar, here is my code of this window (I am using NotifyIcon plugin):

public partial class PointOfSale : Window
{
    TaskbarIcon tb;

    public PointOfSale()
    {
        InitializeComponent();

        tb = (TaskbarIcon)FindResource("NotifyIcon");
        tb.DoubleClickCommand = new ShowWindowCommand();
        tb.Visibility = System.Windows.Visibility.Visible;
        Utils.Utils.SetTaskBarIcon(tb);
   }
}

When the PointOfSale is closed, i check for the closing event and hide it:

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        Utils.Utils.pointOfSale = this;
        Hide();
        e.Cancel = true;
    }

On the Utils.Utils.pointOfSale = this; i save the instance of the actual window, with this i can open it when the icon on the task bar is double clicked.

Ay information about this would be helpful.

EDIT: I think it could also work if the last instance of the application could be killed and the new one instance could be created.

Community
  • 1
  • 1
Fernando Santiago
  • 2,128
  • 10
  • 44
  • 75
  • That code will crash with `NullReferenceException` if you fail to obtain the `mutex` –  Dec 05 '15 at 05:32
  • @Micky, what should i change? – Fernando Santiago Dec 05 '15 at 06:04
  • _"The problem is that my MainWindow is not opened"_ -- why not? Did you debug the code? What happened? Where did the code do something you did not expect? Please provide a good [mcve] that reliably reproduces whatever problem is occurring. Also, please do not combine questions; if you have a separate question about `NotifyIcon`, post that in a different question. – Peter Duniho Dec 05 '15 at 06:09
  • 1
    for anyone having the same problem, here is the [solution](http://codereview.stackexchange.com/questions/20871/single-instance-wpf-application) – Fernando Santiago Dec 07 '15 at 19:40

1 Answers1

0

Start with the simplest possible implementation of a WPF application and get it to work as a singleton - then you can re-incorporate that implementation into whatever complex application that you are building.

Here is an outline that you can use. This is really explained many times over on SO...

Generate a boilerplate WPF application in VS, and modify App.xaml.cs as follows (and make note of the comments in the code that suggest a few additional changes).

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;

namespace Singleton
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    /// <remarks>
    /// 1. Change Build Action for App.xaml (right-click, Properties)
    ///     to Page from ApplicaitonDefinition
    /// 2. Go to project settings, and in the Debug tab, uncheck 
    ///     "Enable Visual Studio Hosting Process"
    /// </remarks>
    public partial class App : Application
    {
        [STAThread]
        public static void Main(string[] args)
        {
            bool bNew = true;
            using (Mutex mutex = new Mutex(true, "Singleton-GUID", out bNew)) // Replace string "Singleton_GUID" with one with a real GUID
            {
                if(bNew)
                {
                    new App().Run();
                }
                else
                {
                    Process me = Process.GetCurrentProcess();
                    List<Process> processes = new List<Process>(Process.GetProcesses());

                    var matches = 
                        processes.FindAll((p) => 
                        {
                            return 
                                string.Equals(p.ProcessName, me.ProcessName, StringComparison.InvariantCultureIgnoreCase) && 
                                (p.Id != me.Id);
                        });

                    if (matches.Count == 1)
                    {
                        Process prior = matches[0];
                        if (prior.MainWindowHandle != IntPtr.Zero)
                        {
                            NativeMethods.ShowWindow(prior.MainWindowHandle, NativeMethods.SH_SHOW);
                        }
                    }
                }
            }
        }

        private App()
        {
            InitializeComponent();
        }
    }

    public static class NativeMethods
    {
        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        public const int SH_SHOW = 5;
    }
}
Vatsan
  • 1,163
  • 9
  • 15
  • What do you mean by 'Replace string "Singleton_GUID" with one with a real GUID' do i have to get the GUID string from the application or a the window class i want to open? – Fernando Santiago Dec 07 '15 at 16:17
  • No, just generate a new guid and use it. It is meant to provide uniqueness to the string. – Vatsan Dec 07 '15 at 18:20