【WPF】WindowChrome的功能详解
参考:https://blog.csdn.net/WPwalter/article/details/81121829
测试环境:.net6.0+wpf+vs2022
Windows结构
标准窗口由两个重叠的矩形组成。 外部矩形(灰色)是 非工作区WindowChrome,内部矩形(白色)是 工作区(client area )。
WindowChrome定义了Window non-client area(即chrome)的外观和行为, 在Window上应用WindowChrome的WindowChrome附加属性即可将Window的non-client area替换为WindowChrome(绕口)
WindowChrome 重新Window non-client area(即chrome)的外观和行为。允许将工作区的扩展至整个窗口。但是在WindowChrome的区域不能交互。如果要交互 就必须设置WindowChrome区域元素的
命中测试。给在WindowChrome区域的元素添加【WindowChrome.IsHitTestVisibleInChrome="True"】附加属性。这样WindowChrome区域的元素就可以交互了。
标题栏:提供 双击最大化、双击最小化、标题、logo、拖、系统菜单
窗体边框:标题按钮 (最小化、最大化和关闭)、阴影效果、调整窗体大小、边框大小。
工作区:提供 应用程序的内容,并由应用程序绘制和管理
GlassFrame
从Vista到Windows10,都有AERO毛玻璃的特效。
这种效果是由DWM(Desktop Window Manager)来控制的。对于一般的程序,默认将在窗口边框应用这种效果。但如果我们想要更多的控制,比如让客户区的一部分也呈现这种效果,那也非常的简单。不需要我们在程序里做任何复杂的算法,我们只需要调API(在dwmapi.dll中),交给DWM去做就可以了。
C# WPF中可通过设置WindowChrome的WindowChrome.GlassFrameThickness=“任意负数”来实现工作区有AERo特效。
运行后效果。
WindowChrome结构
WindowChrome定义了Window non-client area(即chrome)的外观和行为, 在Window上应用WindowChrome的WindowChrome附加属性即可将Window的non-client area替换为WindowChrome(绕口)
【结构解析】
非工作区(no-client-area)=标题栏+窗体边框
标题栏:双击最大化、双击最小化、拖拽、系统菜单.默认情况下,窗口标题区域中的任何视觉元素部分不交互。 若要在标题区域中启用交互式元素,请将 IsHitTestVisibleInChrome 附加属性附加到元素并将其设置为 true
。
窗体边框:阴影效果、调整窗体大小、边框大小。默认使用GlassFrame(毛玻璃边框)作为窗体边框,如果不想使用GlassFrame,就将设置WindowChrome.GlassFrameThickness=“0”,此举也会将禁用标准标题按钮 (最大化、最小化、关闭) 和交互。
工作区域:呈现窗体布局。
当给窗体控件添加WindowChrome.WindowChrome附加属性时候, 标题处于窗体控件的最顶层,工作区处于中间层,GlassFrame处于最底层。
依赖属性
- CaptionHeight:CaptionHeight指定WindowChrome的标题栏高度,处于窗体图层的最顶层。它不影响外观,因为WindowChrome的标题栏范围实际是不可见的,它包括可以拖动窗体、双击最大化窗体、右键打开SystemMenu等行为。默认情况下,窗口标题区域中的任何视觉元素部分不交互。 若要在标题区域中启用交互式元素,请将 IsHitTestVisibleInChrome 附加属性附加到元素并将其设置为
true
。 - UseAeroCaptionButtons:UseAeroCaptionButtons表示标题栏上的那三个默认按钮是否可以命中,因为我们想要自己管理这三个按钮的样式、显示或隐藏,所以设置为False。
- CornerRadius:工作区 边角的度数
- GlassFrameCompleteThickness:
- GlassFrameThickness:控制非工作区域四边的宽度,默认情况下,玻璃框架(GlassFrame)将使用系统值来模拟标准窗口的外观。 如果已启用 Windows Aero,则启用标准标题按钮 (最大化、最小化、关闭) 和交互。 若要使没有玻璃框架的自定义窗口,请将此厚度设置为统一值 0。 这将禁用标准标题按钮。若要扩展玻璃框架以覆盖整个窗口,请将 GlassFrameThickness 属性设置为任意一端的负值。例如:
GlassFrameThickness="0 64 0 0"或者
GlassFrameThickness="0"、
GlassFrameThickness="-1"
- NonClientFrameEdges:表示窗口框架边缘是否归工作区域所有、“Left, Right, Top, Bottom”不是有效的值。 至少一个边缘必须属于非工作区域。。例如:NonClientFrameEdges="Left,Bottom,Right" 表示只显示顶部 边框 。特别注意:可定制区域中顶部是包含那 1 像素的边距的,但其他三边不包含。
- ResizeBorderThickness:向窗口内部扩展拖动缩放 区域
附加属性
- IsHitTestVisibleInChrome:GlassFrameThickness和CaptionHeight定义了Chrome的范围,默认情况下任何在Chrome的范围内的元素都不可以交互,如果需要在标题栏放自己的按钮(或其它交互元素)需要将这个按钮的WindowsChrome.IsHitTestVisibleInChrome附加属性设置为True。
一、标题栏设置
标题栏(Caption):标题栏处于窗体图层的最顶层。它不影响外观,因为WindowChrome的标题栏范围实际是不可见的,它包括可以拖动窗体、双击最大化窗体、右键打开SystemMenu等行为。默认情况下,窗口标题区域中的任何视觉元素部分不交互。 若要在标题区域中启用交互式元素,请将 IsHitTestVisibleInChrome 附加属性附加到元素并将其设置为 true
。
非工作区=标题栏+边框
CaptionHeight属性
CaptionHeight:CaptionHeight指定WindowChrome的标题栏高度
Caption标题栏放置在 GlassFrameThickness.top
边框上,当GlassFrameThickness.top
=“0” 标题栏就被隐藏了。 下面案例 设置不同的GlassFrameThickness.top宽度
和标题栏的高度CaptionHeight,通过拖拽就可以看出不同。
<WindowChrome.WindowChrome> <WindowChrome GlassFrameThickness="50" CaptionHeight="30" NonClientFrameEdges="Left,Bottom,Right" CornerRadius="20" /> </WindowChrome.WindowChrome>
UseAeroCaptionButtons属性
UseAeroCaptionButtons表示标题栏上的那三个默认按钮是否可以命中,因为我们想要自己管理这三个按钮的样式、显示或隐藏,所以设置为False。
案例:UseAeroCaptionButtons="False",最大,最小,关闭按钮将不会命中。
<WindowChrome.WindowChrome> <WindowChrome GlassFrameThickness="0,50,0,0" CaptionHeight="30" NonClientFrameEdges="None" UseAeroCaptionButtons="False" /> </WindowChrome.WindowChrome>
二 、工作区设置
工作区(client area):处于窗体图层的中间层,显示窗体布局。
CornerRadius 属性
控制工作区 边角弧度。
实例如下:
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="0" CaptionHeight="30" NonClientFrameEdges="None" CornerRadius="20" />
</WindowChrome.WindowChrome>
效果如下:
GlassFrameThickness="0"因此窗体边框被隐藏,剩下全部都是透明的,黑色代表透明。虽然边框隐藏了,但是标题栏和工作区依然存在。
三、边框设置(frame)
边框(frame):处于窗体图层的最底层,控制边框、阴影
非工作区=标题栏+边框
GlassFrameThickness
属性
控制WindowChrome的四边边框 宽度。 0表示不使用系统按钮【后面介绍】,-1表示用的系统默认值。例如:GlassFrameThickness="0 64 0 0"或者
GlassFrameThickness="0"、
GlassFrameThickness="-1"
//其他样式省略
<WindowChrome.WindowChrome> <WindowChrome GlassFrameThickness="50" /> </WindowChrome.WindowChrome>
效果如下
黑色代表透明。此时窗体没有任何内容,所有只显示了WindowChrome的外观。
GlassFrameThickness 值为 -1 效果如下:
在官方文档 WindowChrome.GlassFrameCompleteThickness Property (System.Windows.Shell) 中有说,如果指定 GlassFrameThickness 值为 -1,那么可以做到整个窗口都遮挡,但实际上全遮挡的效果也是不对劲的,就像下面这样:
GlassFrameThickness 为 -1
不止边框颜色不见了,连右上角的三个按钮的位置都跟原生不同,这个窗口的位置不贴边。
显然,GlassFrameThickness
属性我们不能指定为 -1。也不能指定为 0,你可以试试,会发现连阴影都不见了,这更不是我们想要的效果。
GlassFrameThickness 值为0 效果如下
那我们指定为其他正数呢?
显然,没有一个符合我们的要求。但好在我们还有一个属性可以尝试 —— NonClientFrameEdges
。官方文档 WindowChrome.NonClientFrameEdges Property (System.Windows.Shell) 对此的解释是:即指定哪一边不属于客户区。
NonClientFrameEdge属性
即指定哪一边不属于客户区。
可以NonClientFrameEdges设置取消 边框。如下代码:
<WindowChrome.WindowChrome>
<WindowChrome NonClientFrameEdges="Left,Bottom,Right" />
</WindowChrome.WindowChrome>
效果如下:
ResizeBorderThickness
属性
向窗口内部扩展拖动缩放 区域
<Window x:Class="WpfApp2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <WindowChrome.WindowChrome> <WindowChrome ResizeBorderThickness="100"></WindowChrome> </WindowChrome.WindowChrome> <Grid Background="Transparent" MouseDown="UIElement_OnMouseDown"> <Grid Margin="100" Background="White" /> <Button Width="100" Height="100" Command="Undo" /> </Grid> </Window>
效果如下:
WindowChrome.IsHitTestVisibleInChrome 附加属性
WindowChrome 重新Window non-client area(即chrome)的外观和行为。允许将工作区的扩展至整个窗口。但是在WindowChrome的区域不能交互。如果要交互 就必须设置WindowChrome区域元素的
命中测试。给在WindowChrome区域的元素添加【WindowChrome.IsHitTestVisibleInChrome="True"】附加属性。这样WindowChrome区域的元素就可以交互了。