Windows 系统中有一个没什么文档的 API,SetWindowCompositionAttribute
,可以允许应用的开发者将自己窗口中的内容渲染与窗口进行组合。这可以实现很多系统中预设的窗口特效,比如 Windows 7 的毛玻璃特效,Windows 8/10 的前景色特效,Windows 10 的模糊特效,以及 Windows 10 1709 的亚克力(Acrylic)特效。而且这些组合都发生在 dwm 进程中,不会额外占用应用程序的渲染性能。
本文介绍 SetWindowCompositionAttribute
可以实现的所有效果。你可以通过阅读本文了解到与系统窗口可以组合渲染到哪些程度。
本文内容
试验用的源代码
本文将创建一个简单的 WPF 程序来验证 SetWindowCompositionAttribute
能达到的各种效果。你也可以不使用 WPF,得到类似的效果。
简单的项目文件结构是这样的:
- [项目] Walterlv.WindowComposition
- App.xaml
- App.xaml.cs
- MainWindow.xaml
- MainWindow.xaml.cs
- WindowAccentCompositor
其中,App.xaml 和 App.xaml.cs 保持默认生成的不动。
为了验证此 API 的效果,我需要将 WPF 主窗口的背景色设置为纯透明或者 null
,而设置 ControlTemplate
才能彻彻底底确保所有的样式一定是受我们自己控制的,我们在 ControlTemplate
中没有指定任何可以显示的内容。MainWindow.xaml 的全部代码如下:
<Window x:Class="Walterlv.WindowComposition.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="欢迎访问吕毅的博客:blog.walterlv.com" Height="450" Width="800">
<Window.Template>
<ControlTemplate TargetType="Window">
<AdornerDecorator>
<ContentPresenter />
</AdornerDecorator>
</ControlTemplate>
</Window.Template>
<!-- 我们注释掉 WindowChrome,是因为即将验证 WindowChrome 带来的影响。 -->
<!--<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="-1" />
</WindowChrome.WindowChrome>-->
<Grid>
</Grid>
</Window>
而 MainWindow.xaml.cs 中,我们简单调用一下我们即将写的调用 SetWindowCompositionAttribute
的类型。
using System.Windows;
using System.Windows.Media;
using Walterlv.Windows.Effects;
namespace Walterlv.WindowComposition
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var compositor = new WindowAccentCompositor(this);
compositor.Composite(Color.FromRgb(0x18, 0xa0, 0x5e));
}
}
}
还剩下一个 WindowAccentCompositor.cs 文件,因为比较长放到博客里影响阅读,所以建议前往这里查看:
而其中对我们最终渲染效果有影响的就是 AccentPolicy
类型的几个属性。其中 AccentState
属性是下面这个枚举,而 GradientColor
将决定窗口渲染时叠加的颜色。
private enum AccentState
{
ACCENT_DISABLED = 0,
ACCENT_ENABLE_GRADIENT =