【发布时间】:2019-05-16 19:52:32
【问题描述】:
我正在尝试使用具有以下 XAML 属性的 C# 和 WPF 创建一个窗口:
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 动画都丢失了。至少包括:
- 第一次显示窗口时的淡入效果。
- 最小化效果(从按钮或任务栏最小化窗口时)。
- 最大化/恢复动画。
- 关闭窗口时的关闭动画。
感谢 reddit 用户 draxus99 的帮助,我能够使用 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 事件之前设置窗口样式。
【问题讨论】:
-
你最终想要完成什么?
-
我正在尝试制作一个 WPF 窗口,我可以在其中绘制也支持透明度的非客户区。我可以使用我的帖子中描述的方法来做到这一点,但是会出现缺少动画的问题(由于borderstyle = none)。如果我在 Window_Loaded 事件中更改窗口样式,最小/最大/恢复动画效果很好,但是打开/关闭表单时的淡入和淡出丢失了。
-
类似this?
-
我想要的效果有点相似,但我不知道该链接中的解决方案是否适用于我的情况,因为我需要使用 WindowChrome 类将非客户区扩展到窗口(或 DwmExtendFrameIntoClientArea,如果我使用的是没有 WindowChrome 类的不同语言)。
-
这是一个视频,它比我能解释的更清楚地说明了我的意思。我首先展示了代码,然后是运行动画演示的程序,但请注意,当第一次打开或关闭表单时,它只是弹出和消失而不是淡入。在视频结束时,我关闭了一个资源管理器窗口演示表单应具有的微妙淡入淡出效果。 youtu.be/3eDyUbmuDDk