wpf 在WindowLoaded中设置WindowStyle时,如何恢复窗口的默认显示/关闭动画?

sg3maiej  于 2023-06-07  发布在  Windows
关注(0)|答案(2)|浏览(265)

我正在尝试使用C#和WPF创建一个具有以下XAML属性的窗口:

WindowStyle="None"
    AllowsTransparency="True"

设置这些值会删除所有标准窗口功能,但我可以使用WindowChrome类恢复大部分功能,如下所示:

<WindowChrome.WindowChrome>
        <WindowChrome CaptionHeight="25" ResizeBorderThickness="7" />
    </WindowChrome.WindowChrome>

接下来,我创建自己的按钮来替换标题栏中不再存在的按钮,并设置它们的行为:

private void minimizeButton_Click(object sender, RoutedEventArgs e)
    {
        SystemCommands.MinimizeWindow(this);
    }

    private void closeButton_Click(object sender, RoutedEventArgs e)
    {
        SystemCommands.CloseWindow(this);
    }

    private void MaximizeButton_Click(object sender, RoutedEventArgs e)
    {
        if(WindowState == WindowState.Normal)
        {
            SystemCommands.MaximizeWindow(this);
        }
        else
        {
            SystemCommands.RestoreWindow(this);
        }
    }

这是可行的,但是因为我将WindowStyle设置为none,所以所有本机Window动画都丢失了。至少包括:
1.窗口首次显示时的淡入效果。
1.最小化效果(当从按钮或任务栏最小化窗口时)。
1.最大化/恢复动画。
1.关闭窗口时的关闭动画。
感谢reddit用户draxus 99的帮助,我能够使用WindowsAPI恢复最小化和最大化/恢复动画(上面列表中的2号和3号),如下所示:

[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
    private static extern int SetWindowLong32(HandleRef hWnd, int nIndex, int dwNewLong);

    [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
    private static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, IntPtr dwNewLong);

    public IntPtr myHWND;
    public const int GWL_STYLE = -16;

    public static class WS
    {
        public static readonly long
        WS_BORDER = 0x00800000L,
        WS_CAPTION = 0x00C00000L,
        WS_CHILD = 0x40000000L,
        WS_CHILDWINDOW = 0x40000000L,
        WS_CLIPCHILDREN = 0x02000000L,
        WS_CLIPSIBLINGS = 0x04000000L,
        WS_DISABLED = 0x08000000L,
        WS_DLGFRAME = 0x00400000L,
        WS_GROUP = 0x00020000L,
        WS_HSCROLL = 0x00100000L,
        WS_ICONIC = 0x20000000L,
        WS_MAXIMIZE = 0x01000000L,
        WS_MAXIMIZEBOX = 0x00010000L,
        WS_MINIMIZE = 0x20000000L,
        WS_MINIMIZEBOX = 0x00020000L,
        WS_OVERLAPPED = 0x00000000L,
        WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
        WS_POPUP = 0x80000000L,
        WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU,
        WS_SIZEBOX = 0x00040000L,
        WS_SYSMENU = 0x00080000L,
        WS_TABSTOP = 0x00010000L,
        WS_THICKFRAME = 0x00040000L,
        WS_TILED = 0x00000000L,
        WS_TILEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
        WS_VISIBLE = 0x10000000L,
        WS_VSCROLL = 0x00200000L;
    }

    public static IntPtr SetWindowLongPtr(HandleRef hWnd, int nIndex, IntPtr dwNewLong)
    {
        if (IntPtr.Size == 8)
        {
            return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
        }
        else
        {
            return new IntPtr(SetWindowLong32(hWnd, nIndex, dwNewLong.ToInt32()));
        }
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        myHWND = new WindowInteropHelper(this).Handle;
        IntPtr myStyle = new IntPtr(WS.WS_CAPTION | WS.WS_CLIPCHILDREN | WS.WS_MINIMIZEBOX | WS.WS_MAXIMIZEBOX | WS.WS_SYSMENU | WS.WS_SIZEBOX);
        SetWindowLongPtr(new HandleRef(null, myHWND), GWL_STYLE, myStyle);
    }

问题是,当窗口第一次打开时通常显示的淡入动画和当窗口关闭时的淡出动画都丢失了,所以当打开或关闭程序时,窗口只是弹出和消失,而不是显示正常的淡入淡出过渡。我怀疑缺少的关闭动画可能是由于我将关闭按钮单击动作绑定到:

SystemCommands.CloseWindow(this);

这可能是在动画有机会显示之前关闭窗口,但我不知道为什么初始淡入动画不显示,除非我需要设置窗口样式,甚至早于Window_Loaded事件。

xcitsw88

xcitsw881#

这个答案是相当晚了几年,但我使用的是draxus99的修复,你在你的问题,并有相同的问题与打开和关闭窗口动画失踪,直到我偶然发现的原因。
事实证明,为您的窗口添加AllowsTransparency="True"不仅会删除窗口的默认边框(例如Windows 11的圆形边缘和边框颜色),而且还可以摆脱draxus99修复应该提供的打开和关闭动画。通过删除这条线,您将恢复这些功能。这样做的唯一缺点是,您将错过任何需要将AllowsTransparency设置为true的内容,这似乎是您面临的问题。但是,除非你打算为你的窗口制作自己的圆角,或者在窗口中有一些透明的位,否则你不应该这样做,因为它会损害性能(从我所读到的)。
此外,如果有读者在尝试使用draxus99的修复时遇到麻烦,请参阅我使用它来恢复我参与的项目的启动器的窗口动画的示例:https://github.com/SubnauticaNitrox/Nitrox/pull/2031/files。它被那里的一个其他开发人员重构,以更好地适应这个特定项目的结构,但你应该能够复制它供自己使用。

mcdcgff0

mcdcgff02#

尝试使用属性Opacity设置淡入/淡出动画,如this answer手动设置。比如:

<Window.Triggers>
        <EventTrigger RoutedEvent="Window.Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation Duration="00:00:01" Storyboard.TargetProperty="Opacity" From="0" To="1" Completed="fadeCompleted" />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Window.Triggers>

相关问题