【问题标题】:How to create single instance WPF Application that restores the open window when an attempt is made to open another instance? [duplicate]如何创建单实例 WPF 应用程序以在尝试打开另一个实例时恢复打开的窗口? [复制]
【发布时间】:2014-02-14 21:34:10
【问题描述】:

对不起,标题很难理解。我不知道该怎么说。

我有一个应用程序,应该只允许每个用户会话运行一个实例。 如果用户再次单击以启动应用程序,我想将已经聚焦的那个。

该窗口可能具有折叠的可见性。

如果它是可见的,我知道我可以使用

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

SetForegroundWindow(hWnd);

但是如果窗口被折叠,我有办法让它恢复可见吗?

【问题讨论】:

    标签: c# wpf


    【解决方案1】:

    您正在寻找Mutex Class。这相当复杂,但幸运的是单例模式已被广泛讨论。有几篇关于它的好文章,但你可以在 Sanity Free Coding 网站上的 C# .NET Single Instance Application 页面中找到它的一个很好的实现。从链接页面:

    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");
            }
        }
    }
    

    现在您可能想知道如何在 WPF 应用程序中使用 Main 方法,对吧?好吧,您必须做一些事情,但这并不难。请参阅Writing a custom Main() method for WPF applications 文章,其中详细解释了这一点。从那篇文章:

    您基本上需要将应用程序的构建操作从“应用程序定义”更改为“页面”,创建一个调用“InitializeComponent”的构造函数,并通过最终调用应用程序的“运行”方法重载之一来编写您的 Main()。 ...不要忘记从 App.xaml 中删除“StartupUri”,否则将显示另一个窗口副本(除非您收到错误,因为 URI 指向不存在的 XAML 资源)。

    因此,通过合并这两个资源,我们可以看到您的 App.xaml.cs 文件应如下所示:

    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;
            }
        }
    }
    

    【讨论】:

    • 在我看来,上面放弃了第一个应用程序实例中的互斥锁。来自文档:“拥有互斥锁的线程可以在重复调用 WaitOne 时请求相同的互斥锁,而不会阻止其执行。但是,线程必须调用 ReleaseMutex 方法相同的次数才能释放互斥锁的所有权” 。创建互斥锁时,如果您是第一个实例,则互斥锁已经获得;然后您通过调用WaitOne() 再次获取它。如果要获得两次,则需要释放两次。
    【解决方案2】:

    我从 App.xaml 文件中删除了标签 StartupUri

    将 App.xaml 的 Build Action 由 ApplicationDefinition 更改为 Page(您可以在属性窗口中更改)。

    添加对Microsoft.VisualBasic 的引用(WindowsFormsApplicationBase 的命名空间)。

    App.xaml.cs类上,输入以下代码:

    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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多