Esempio n. 1
0
		internal static void Restore(Window window) => window.ClearValue(Window.WindowStateProperty);
Esempio n. 2
0
 public static void Restore(Window window)
 {
     window.ClearValue(Window.WindowStateProperty);
 }
        /// <summary>
        /// 退出全屏模式
        /// 窗口会回到进入全屏模式时保存的状态
        /// 退出全屏模式后会重新启用 DWM 过渡动画
        /// </summary>
        public static void EndFullScreen(System.Windows.Window window)
        {
            if (window == null)
            {
                throw new ArgumentNullException(nameof(window), $"{nameof(window)} 不能为 null");
            }

            //确保在全屏模式并获取之前保存的状态
            if (window.GetValue(BeforeFullScreenWindowPlacementProperty) is InteropValues.WINDOWPLACEMENT placement
                && window.GetValue(BeforeFullScreenWindowStyleProperty) is InteropValues.WindowStyles style)
            {
                var hwnd = new WindowInteropHelper(window).Handle;

                if (hwnd == IntPtr.Zero)
                {
                    // 句柄为 0 只有两种情况:
                    //  1. 虽然窗口已进入全屏,但窗口已被关闭;
                    //  2. 窗口初始化前,在还没有调用 StartFullScreen 的前提下就调用了此方法。
                    // 所以,直接 return 就好。
                    return;
                }


                var hwndSource = HwndSource.FromHwnd(hwnd);

                //去除hook
                hwndSource.RemoveHook(KeepFullScreenHook);

                //恢复保存的状态
                //不要改变Style里的WS_MAXIMIZE,否则会使窗口变成最大化状态,但是尺寸不对
                //也不要设置回Style里的WS_MINIMIZE,否则会导致窗口最小化按钮显示成还原按钮
                InteropMethods.SetWindowLong(hwnd, InteropValues.GWL_STYLE,
                    (IntPtr) (style & ~(InteropValues.WindowStyles.WS_MAXIMIZE | InteropValues.WindowStyles.WS_MINIMIZE)));

                if ((style & InteropValues.WindowStyles.WS_MINIMIZE) != 0)
                {
                    //如果窗口进入全屏前是最小化的,这里不让窗口恢复到之前的最小化状态,而是到还原的状态。
                    //大多数情况下,都不期望在退出全屏的时候,恢复到最小化。
                    placement.showCmd = InteropValues.SW.RESTORE;
                }

                if ((style & InteropValues.WindowStyles.WS_MAXIMIZE) != 0)
                {
                    //提前调用 ShowWindow 使窗口恢复最大化,若通过 SetWindowPlacement 最大化会导致闪烁,只靠其恢复 RestoreBounds.
                    InteropMethods.ShowWindow(hwnd, InteropValues.SW.MAXIMIZE);
                }

                InteropMethods.SetWindowPlacement(hwnd, ref placement);

                if ((style & InteropValues.WindowStyles.WS_MAXIMIZE) ==
                    0) //如果窗口是最大化就不要修改WPF属性,否则会破坏RestoreBounds,且WPF窗口自身在最大化时,不会修改 Left Top Width Height 属性
                {
                    if (InteropMethods.GetWindowRect(hwnd, out var rect))
                    {
                        //不能用 placement 的坐标,placement是工作区坐标,不是屏幕坐标。

                        //确保窗口的 WPF 属性与 Win32 位置一致
                        var logicalPos =
                            hwndSource.CompositionTarget.TransformFromDevice.Transform(
                                new Point(rect.Left, rect.Top));
                        var logicalSize =
                            hwndSource.CompositionTarget.TransformFromDevice.Transform(
                                new Point(rect.Width, rect.Height));
                        window.Left = logicalPos.X;
                        window.Top = logicalPos.Y;
                        window.Width = logicalSize.X;
                        window.Height = logicalSize.Y;
                    }
                }

                //重新启用 DWM 过渡动画 忽略返回值,若DWM关闭不做处理
                InteropMethods.DwmSetWindowAttribute(hwnd, InteropValues.DwmWindowAttribute.DWMWA_TRANSITIONS_FORCEDISABLED, 0,
                    sizeof(int));

                //删除保存的状态
                window.ClearValue(BeforeFullScreenWindowPlacementProperty);
                window.ClearValue(BeforeFullScreenWindowStyleProperty);
            }
        }