WPF Single Instance Best Practices

前端 未结 11 1537
名媛妹妹
名媛妹妹 2020-12-07 08:19

This is the code I implemented so far to create a single instance WPF application:

#region Using Directives
using System;
using System.Globalization;
using S         


        
11条回答
  •  暖寄归人
    2020-12-07 09:26

    to prevent a second instance (and signal the existing),

    • using EventWaitHandle (since we are talking about an event),
    • using Task,
    • no Mutex code required,
    • no TCP,
    • no Pinvokes,
    • no GarbageCollection stuff,
    • thread save
    • simple

    it could be done like this (this for an WPF app (see ref to App()), but works on WinForms as well):

    public partial class App : Application
    {
        public App()
        {
            // initiate it. Call it first.
            preventSecond();
        }
    
        private const string UniqueEventName = "{GENERATE-YOUR-OWN-GUID}";
    
        private void preventSecond()
        {
            try
            {
                EventWaitHandle.OpenExisting(UniqueEventName); // check if it exists
                this.Shutdown();
            }
            catch (WaitHandleCannotBeOpenedException)
            {
                new EventWaitHandle(false, EventResetMode.AutoReset, UniqueEventName); // register
            }
        }
    }
    

    Second version: above plus signaling the other instance to show the window (change the MainWindow part for WinForms):

    public partial class App : Application
    {
        public App()
        {
            // initiate it. Call it first.
            //preventSecond();
            SingleInstanceWatcher();
        }
    
        private const string UniqueEventName = "{GENERATE-YOUR-OWN-GUID}";
        private EventWaitHandle eventWaitHandle;
    
        /// prevent a second instance and signal it to bring its mainwindow to foreground
        /// 
        private void SingleInstanceWatcher()
        {
            // check if it is already open.
            try
            {
                // try to open it - if another instance is running, it will exist , if not it will throw
                this.eventWaitHandle = EventWaitHandle.OpenExisting(UniqueEventName);
    
                // Notify other instance so it could bring itself to foreground.
                this.eventWaitHandle.Set();
    
                // Terminate this instance.
                this.Shutdown();
            }
            catch (WaitHandleCannotBeOpenedException)
            {
                // listen to a new event (this app instance will be the new "master")
                this.eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, UniqueEventName);
            }
    
            // if this instance gets the signal to show the main window
            new Task(() =>
            {
                while (this.eventWaitHandle.WaitOne())
                {
                    Current.Dispatcher.BeginInvoke((Action)(() =>
                    {
                        // could be set or removed anytime
                        if (!Current.MainWindow.Equals(null))
                        {
                            var mw = Current.MainWindow;
    
                            if (mw.WindowState == WindowState.Minimized || mw.Visibility != Visibility.Visible)
                            {
                                mw.Show();
                                mw.WindowState = WindowState.Normal;
                            }
    
                            // According to some sources these steps are required to be sure it went to foreground.
                            mw.Activate();
                            mw.Topmost = true;
                            mw.Topmost = false;
                            mw.Focus();
                        }
                    }));
                }
            })
            .Start();
        }
    }
    

    This code as a drop in class, will be @ Selfcontained-C-Sharp-WPF-compatible-utility-classes / Utils.SingleInstance.cs

提交回复
热议问题