maui中怎么实现隐藏窗口

maui中怎么实现隐藏窗口 托盘隐藏窗口 系统托盘显示窗口

maui中怎么实现隐藏窗口 maui中怎么实现系统托盘显示窗口

关闭事件拦截,通过系统托盘图标右键退出关闭

#if WINDOWS
            builder.ConfigureLifecycleEvents(events =>
            {
                events.AddWindows(wndLifeCycleBuilder =>
                {
                    wndLifeCycleBuilder.OnWindowCreated(window =>
                    {
                        IntPtr nativeWindowHandle = WinRT.Interop.WindowNative.GetWindowHandle(window);
                        WindowId win32WindowsId = Win32Interop.GetWindowIdFromWindow(nativeWindowHandle);
                        AppWindow winuiAppWindow = AppWindow.GetFromWindowId(win32WindowsId);

                        // 保持标题栏和边框显示	
                        window.ExtendsContentIntoTitleBar = false;

                        if (winuiAppWindow.Presenter is OverlappedPresenter p)
                        {
                            p.IsAlwaysOnTop = false;
                            p.IsResizable = true;
                            p.IsMaximizable = true;
                            p.IsMinimizable = true;
                            p.SetBorderAndTitleBar(true, true);

                            // 设置初始窗口大小和居中位置
                            var displayArea = DisplayArea.Primary;
                            var scalingFactor = ((MauiWinUIWindow)Application.Current?.Windows[0].Handler.PlatformView)?.GetDisplayDensity() ?? 1;
                            var width = 500 * scalingFactor;
                            var height = 700 * scalingFactor;
                            var centerX = (displayArea.WorkArea.Width - width) / 2;
                            var centerY = (displayArea.WorkArea.Height - height) / 2;
                            winuiAppWindow.MoveAndResize(new((int)centerX, (int)centerY, (int)width, (int)height), displayArea);

                            events.AddWindows(windows =>
                            { 
                                WindowExtensions.Hwnd = nativeWindowHandle;
                                WindowExtensions.Show = () =>
                                {
                                    WindowExtensions.BringToFront();
                                    var displyArea = DisplayArea.Primary;
                                    var scalingFactor = ((MauiWinUIWindow)Application.Current?.Windows[0].Handler.PlatformView)?.GetDisplayDensity() ?? 1;
                                    var width = 500 * scalingFactor;
                                    var height = 700 * scalingFactor;
                                    // 右键打开时窗口居中显示
                                    var centerX = (displyArea.WorkArea.Width - width) / 2;
                                    var centerY = (displyArea.WorkArea.Height - height) / 2;
                                    winuiAppWindow.MoveAndResize(new((int)centerX, (int)centerY, (int)width, (int)height), displyArea);
                                    winuiAppWindow.Show();
                                };
                                WindowExtensions.Hide = () =>
                                {
                                    winuiAppWindow.Hide();
                                };
                                WindowExtensions.Close = () =>
                                {
                                    ((MauiWinUIWindow)Application.Current?.Windows[0].Handler.PlatformView)?.Close();
                                };

                                windows.OnLaunched((_, _) =>
                                {
                                });
                                // 关闭事件拦截,通过系统托盘图标右键退出关闭,
                                windows.OnClosed((_, args) =>
                                {
                                    Console.WriteLine( "");
                                    var trayService = Application.Current?.Handler?.MauiContext?.Services?.GetService<ITrayService>();
                                    //trayService.tray.dispose();
                                    trayService.HideClickHandler?.Invoke(); 
                                    args.Handled = true;

                                    //Application.Current.Quit();
                                    //var trayService = Application.Current?.Handler?.MauiContext?.Services?.GetService<ITrayService>();
                                    //if (trayService != null && !trayService.isDispose)
                                    //{
                                    //    args.Handled = true;
                                    //    WindowExtensions.Hide();
                                    //} 
                                    // 正常的关闭行为,不再拦截
                                });
                            });
                        }

                        // 移除初始隐藏窗口的代码,让窗口正常显示
                        // winuiAppWindow.Hide(); // 注释掉这行
                    }); 
                });
            });
#endif  检查一下,为什么关闭事件  //Application.Current.Quit(); 如果不调用这个全局退出,就会报错
但是调用了全局退出,触发窗口隐藏 就没意义

我帮你梳理一下你这段 MAUI + WinUI3 的关闭事件逻辑问题。

你遇到的核心点是:

  • OnClosed 事件如果不调用 Application.Current.Quit(),会报错。
  • 但你真正想要的效果是 拦截关闭事件,不退出程序,而是隐藏窗口(比如托盘程序的常见逻辑)。
  • 如果直接调用 Quit(),程序全局退出了,就失去了「最小化到托盘」的意义。

为什么会报错?

在 WinUI3 里,OnClosed 默认是触发 窗口销毁WinAppSDK 停止消息循环整个进程结束。 你虽然 args.Handled = true,但实际上 WinAppSDK 内部已经准备好要销毁 MainWindow 了。

所以:

  • 如果你不调用 Quit(),WinAppSDK 还以为窗口要销毁 → 导致异常。
  • 如果你调用 Quit(),就正常退出 → 但这不符合你要的托盘模式。

正确处理方式

WinUI3 里 OnClosed 并不是「窗口关闭按钮事件」,而是「窗口真的被销毁后」才触发的。 👉 也就是说,你拦截错了事件。

你应该用 OnCloseRequested(即 WinUI 的 AppWindow.Closing 事件),在那个事件里拦截并隐藏窗口。


修改建议

OnWindowCreated 里加上这一段:

winuiAppWindow.Closing += (sender, args) =>
{
    // 拦截关闭
    args.Cancel = true;

    // 隐藏窗口而不是销毁
    winuiAppWindow.Hide();

    // 通知托盘服务更新状态(如果有)
    var trayService = Application.Current?.Handler?.MauiContext?.Services?.GetService<ITrayService>();
    trayService?.HideClickHandler?.Invoke();
};

然后:

  • 不要在 windows.OnClosed 里写拦截逻辑,那是「已经销毁」后的回调,拦不住。
  • Application.Current.Quit() 只在你 真正要退出应用(比如托盘菜单点“退出”)的时候调用。

✅ 总结:

  • AppWindow.Closing 拦截关闭按钮 → 改成隐藏窗口。
  • Application.Current.Quit() 只在「退出菜单」调用,而不是窗口的关闭按钮。
  • windows.OnClosed 可以保留,但那是程序真的要退出时的「清理收尾」事件。

要不要我帮你改写一份 完整可运行的托盘 + 关闭拦截方案(包含 TrayService 调用 + Hide/Show/Quit 三个入口)?

 // 关闭事件拦截,通过系统托盘图标右键退出关闭,
 windows.OnClosed((_, args) =>
 { 
     var trayService = Application.Current?.Handler?.MauiContext?.Services?.GetService<ITrayService>();
     trayService.tray.dispose();
     //trayService.HideClickHandler?.Invoke(); 
     Application.Current.Quit();
     //var trayService = Application.Current?.Handler?.MauiContext?.Services?.GetService<ITrayService>();
     //if (trayService != null && !trayService.isDispose)
     //{
     //    args.Handled = true;
     //    WindowExtensions.Hide();
     //} 
     // 正常的关闭行为,不再拦截
 });
 winuiAppWindow.Closing += (sender, args) =>
 {
     // 拦截关闭
     //args.Cancel = true;//注释后 不拦截窗口关闭,会调用 windows.OnClosed退出应用程序
     // 隐藏窗口而不是销毁
     winuiAppWindow.Hide(); 
 };

隐藏窗口后怎么设置左键系统托盘是否居中 或者是否固定窗口显示位置

隐藏窗口后怎么设置左键系统托盘固定窗口的显示位置

  WindowExtensions.Show = () =>
  {
      WindowExtensions.BringToFront();
      ////左键托盘是否居中
      //var displyArea = DisplayArea.Primary;
      //var scalingFactor = ((MauiWinUIWindow)Application.Current?.Windows[0].Handler.PlatformView)?.GetDisplayDensity() ?? 1;
      //var width = 500 * scalingFactor;
      //var height = 700 * scalingFactor;
      //// 右键打开时窗口居中显示
      //var centerX = (displyArea.WorkArea.Width - width) / 2;
      //var centerY = (displyArea.WorkArea.Height - height) / 2;
      //winuiAppWindow.MoveAndResize(new((int)centerX, (int)centerY, (int)width, (int)height), displyArea);
      
      winuiAppWindow.Show();
  };