如何创建单实例 WPF 应用程序以在尝试打开另一个实例时恢复打开的窗口? [复制]

Posted

技术标签:

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

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

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

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

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

if (IsIconic(hWnd))

    ShowWindowAsync(hWnd, swRestore);


SetForegroundWindow(hWnd);

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

【问题讨论】:

【参考方案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();
    

【讨论】:

以上是关于如何创建单实例 WPF 应用程序以在尝试打开另一个实例时恢复打开的窗口? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 xib 创建单例 UIView 以在不同的 VC 上使用一个实例?

wpf 窗口弹出问题

我应该如何阅读键盘输入以在 WPF 中创建 2D 游戏?

检查 WPF 应用程序的其他实例是不是正在运行 [重复]

访问现有的 WPF 应用程序实例?

如何创建按钮以在VB.Net 2003中打开另一个apx.net网页