当WPF应用程序在后台进程中运行时如何恢复MainWindow

问题描述 投票:0回答:1

在我的 WPF 应用程序的

App.xaml.cs
中,我有一个覆盖函数来启动应用程序。当应用程序启动时,它首先会检查是否有另一个实例正在运行。如果是这样,第二个实例将关闭。然后,它将检查应用程序是否在用户计算机启动时自动启动。如果自动打开,它将使用
MainWindow.Hide()
隐藏该应用程序。然后它订阅主窗口的更改。如果有任何更改,将显示主窗口。 我的代码的目的是在计算机启动时隐藏窗口。然后,如果用户单击 exe 图标,则会显示该窗口。一切工作正常,除了当我单击 exe 图标时,我收到错误消息“应用程序的另一个实例已在运行”。而应用程序实际上在后台进程中运行(我在任务管理器中检查过)。有没有办法在用户单击 exe 时恢复主窗口?

protected override void OnStartup(StartupEventArgs e)
{
    const string mutexName = "YourAppMutexName";

    _mutex = new Mutex(true, mutexName, out bool isNewInstance);

    if (isNewInstance)
    {
        // Another instance of the application is already running
        MessageBox.Show("Another instance of the application is already running.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
        Current.Shutdown();
    }
    else
    {
        base.OnStartup(e);

        bool startedAutomatically = IsStartedAutomatically(e.Args);


        NavigationStore navigationStore = new();

        navigationStore.CurrentVM = new LoginVM(navigationStore);

       
        if (startedAutomatically)
        {
            // The application was started automatically by Windows during startup
            // Do whatever you need to do in this case (e.g., hide the main window)
            MainWindow = new MainWindow()
            {
                DataContext = new MainWindowVM(navigationStore)
            };
            MainWindow.Hide();
            MessageBox.Show("App running but hidden because of auto startup");
            MainWindow.StateChanged += (sender, args) =>
            {
                if (MainWindow.WindowState == WindowState.Normal)
                {
                    MainWindow.Show();
                }
            };
        }
        else
        {
            // The application was started manually by the user
            // Do whatever you need to do in this case (e.g., show the main window)
            MainWindow = new MainWindow()
            {
                DataContext = new MainWindowVM(navigationStore)
            };
            MainWindow.Show();
            MessageBox.Show("App running...");
        }

        AddToStartup();
    }
  private bool IsStartedAutomatically(string[] args)
  {
      // Check if the "--startup" command-line argument is present
      return Array.Exists(args, arg => arg.Equals("--startup", StringComparison.OrdinalIgnoreCase));
  }
c# wpf
1个回答
0
投票

您可以使用同步原语来同步两个进程。 让第一个进程等待第二个进程触发的信号。

出于安全原因,我建议使用

EventWaitHandle
而不是
Mutex

一些备注:

  • 在以前从未显示过的窗口上调用
    Window.Hide
    是没有意义的。
  • 此外,您的条件是错误的,因为您在
    Mutex
    是新实例时关闭应用程序。
  • 出于安全原因,您还应该避免将同步对象的名称声明为
    const
    ,因为这会导致全局变量在程序集外部对其他进程可见。
  • 监听
    Window.StateChanged
    事件是多余的,因为窗口不仅不可见,而且永远不会加载。这意味着它是无状态的。您必须先显示
    Window
    ,然后它才能具有窗口状态。
  • 当您已经在类范围内时,使用
    App
    引用您的
    Application.Curent
    类也是多余的。这并没有什么坏处,但有些人可能会觉得你不知道自己在做什么。

代码的改进示例如下所示:

protected override void OnStartup(StartupEventArgs e)
{
  bool isProcessAlreadyRunning = EventWaitHandle.TryOpenExisting("YourAppMutexName", out EventWaitHandle eventWaitHandle);
  if (!isProcessAlreadyRunning)
  {
    eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, "YourAppMutexName");
    var eventSecurity = new EventWaitHandleSecurity();
    SecurityIdentifier? currentUser = WindowsIdentity.GetCurrent().User;
    var accessRule = new EventWaitHandleAccessRule(currentUser, EventWaitHandleRights.Modify | EventWaitHandleRights.Synchronize, AccessControlType.Allow);
    eventSecurity.AddAccessRule(accessRule);
    eventWaitHandle.SetAccessControl(eventSecurity);

    var mainWindow = new MainWindow();

    // TODO::Do some initialization and when you are done wait for the signal

    MessageBox.Show("App running but hidden because of auto startup");

    eventWaitHandle.WaitOne();

    // We were finally signalled and continue to show the application window
    mainWindow.Show();
  }
  else // Another process of this application is already running
  {
    MessageBox.Show("Another instance of the application is already running.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);

    // Signal the other waiting process and allow it to proceed
    eventWaitHandle.Set();
 
    // End the current process
    Shutdown();

    return;
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.