当前位置: 首页 > news >正文

WPF 制作高性能的透明背景异形窗口(使用 WindowChrome 而不要使用 AllowsTransparency=True)

在 WPF 中,如果想做一个背景透明的异形窗口,基本上都要设置 WindowStyle="None"AllowsTransparency="True" 这两个属性。如果不想自定义窗口样式,还需要设置 Background="Transparent"。这样的设置会让窗口变成 Layered Window,WPF 在这种类型窗口上的渲染性能是非常糟糕的。

本文介绍如何使用 WindowChrome 而不设置 AllowsTransparency="True" 制作背景透明的异形窗口,这可以避免异形窗口导致的低渲染性能。


本文内容

    • 背景透明的异形窗口
    • 如何实现
    • 网上流传的主流方法
    • 性能对比
    • 功能对比

背景透明的异形窗口

如下是一个背景透明异形窗口的示例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZtThHnZZ-1574811718213)(https://blog.walterlv.com/static/posts/2019-09-07-13-16-56.png)]

此窗口包含很大的圆角,还包含 DropShadowEffect 制作的阴影效果。对于非透明窗口来说,这是不可能实现的。

如何实现

要实现这种背景透明的异形窗口,需要为窗口设置以下三个属性:

  • WindowStyle="None"
  • ResizeMode="CanMinimize"ResizeMode="NoResize"
  • WindowChrome.GlassFrameThickness="-1" 或设置为其他较大的正数(可自行尝试设置之后的效果)

如下就是一个最简单的例子,最关键的三个属性我已经高亮标记出来了。

    <Window x:Class="Walterlv.Demo.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
++          WindowStyle="None" ResizeMode="CanMinimize"
            Title="walterlv demo" Height="450" Width="800">
++      <WindowChrome.WindowChrome>
++          <WindowChrome GlassFrameThickness="-1" />
++      </WindowChrome.WindowChrome>
        <Window.Template>
            <ControlTemplate TargetType="Window">
                <Border Padding="64" Background="Transparent">
                    <Border CornerRadius="16" Background="White">
                        <Border.Effect>
                            <DropShadowEffect BlurRadius="64" />
                        </Border.Effect>
                        <ContentPresenter ClipToBounds="True" />
                    </Border>
                </Border>
            </ControlTemplate>
        </Window.Template>
        <Grid>
            <TextBlock FontSize="20" Foreground="#0083d0"
                   TextAlignment="Center" VerticalAlignment="Center">
                <Run Text="欢迎访问吕毅的博客" />
                <LineBreak />
                <Run Text="blog.walterlv.com" FontSize="64" FontWeight="Light" />
            </TextBlock>
        </Grid>
    </Window>

网上流传的主流方法

在网上流传的主流方法中,AllowsTransparency="True" 都是一个必不可少的步骤,另外也需要 WindowStyle="None"。但是我一般都会极力反对大家这么做,因为 AllowsTransparency="True" 会造成很严重的性能问题。

如果你有留意到我的其他博客,你会发现我定制窗口样式的时候都在极力避开设置此性能极差的属性:

  • WPF 使用 WindowChrome,在自定义窗口标题栏的同时最大程度保留原生窗口样式(类似 UWP/Chrome)

性能对比

既然特别说到性能,那也是口说无凭,我们要拿出数据来说话。

以下是我用来测试渲染性能所使用的例子:

测试性能所用的程序

相比于上面的例子来说,主要就是加了背景动画效果,这可以用来测试帧率。

    <Window x:Class="Walterlv.Demo.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            WindowStyle="None" ResizeMode="CanMinimize"
            Title="walterlv demo" Height="450" Width="800">
        <WindowChrome.WindowChrome>
            <WindowChrome GlassFrameThickness="-1" />
        </WindowChrome.WindowChrome>
        <Window.Template>
            <ControlTemplate TargetType="Window">
                <Border Padding="64" Background="Transparent">
                    <Border CornerRadius="16" Background="White">
                        <Border.Effect>
                            <DropShadowEffect BlurRadius="64" />
                        </Border.Effect>
                        <ContentPresenter ClipToBounds="True" />
                    </Border>
                </Border>
            </ControlTemplate>
        </Window.Template>
        <Grid>
++          <Rectangle x:Name="BackgroundRectangle" Margin="0 16" Fill="#d0d1d6">
++              <Rectangle.RenderTransform>
++                  <TranslateTransform />
++              </Rectangle.RenderTransform>
++              <Rectangle.Triggers>
++                  <EventTrigger RoutedEvent="FrameworkElement.Loaded">
++                      <BeginStoryboard>
++                          <BeginStoryboard.Storyboard>
++                              <Storyboard RepeatBehavior="Forever">
++                                  <DoubleAnimation Storyboard.TargetName="BackgroundRectangle"
++                                                   Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"
++                                                   From="800" To="-800" />
++                              </Storyboard>
++                          </BeginStoryboard.Storyboard>
++                      </BeginStoryboard>
++                  </EventTrigger>
++              </Rectangle.Triggers>
++          </Rectangle>
            <TextBlock FontSize="20" Foreground="#0083d0"
                   TextAlignment="Center" VerticalAlignment="Center">
                <Run Text="欢迎访问吕毅的博客" />
                <LineBreak />
                <Run Text="blog.walterlv.com" FontSize="64" FontWeight="Light" />
            </TextBlock>
        </Grid>
    </Window>

那么性能数据表现如何呢?我们让这个窗口在 2560×1080 的屏幕上全屏渲染,得出以下数据:

方案WindowChromeAllowsTransparency
帧率(fps)数值越大越好,60 为最好5919
脏区刷新率(rects/s)数值越大越好11738
显存占用(MB)数值越小越好83.31193.29
帧间目标渲染数(个)数值越大越好21

另外,对于显存的使用,如果我在 7680×2160 的屏幕上全屏渲染,WindowChrome 方案依然保持在 80+MB,而 AllowsTransparency 已经达到惊人的 800+MB 了。

可见,对于渲染性能,使用 WindowChrome 制作的背景透明异形窗口性能完虐使用 AllowsTransparency 制作的背景透明异形窗口,实际上跟完全没有设置透明窗口的性能保持一致。

使用 WindowChrome 制作透明窗口的性能数据

使用 AllowsTransparency 制作透明窗口的性能数据

功能对比

既然 WindowChrome 方法在性能上完虐网上流传的设置 AllowsTransparency 方法,那么功能呢?

值得注意的是,由于在使用 WindowChrome 制作透明窗口的时候设置了 ResizeMode="None",所以你拖动窗口在屏幕顶部和左右两边的时候,Windows 不会再帮助你最大化窗口或者靠边停靠窗口,于是你需要自行处理。不过窗口的标题栏拖动功能依然保留了下来,标题栏上的右键菜单也是可以继续使用的。

方案WindowChromeAllowsTransparency
拖拽标题栏移动窗口保留自行实现
最小化最大化关闭按钮丢失丢失
拖拽边缘调整窗口大小丢失丢失
移动窗口到顶部可最大化丢失自行实现
拖拽最大化窗口标题栏还原窗口保留自行实现
移动窗口到屏幕两边可侧边停靠丢失自行实现
拖拽摇动窗口以最小化其他窗口保留自行实现
窗口打开/关闭/最小化/最大化/还原动画丢失丢失

表格中:

  • 保留 表示此功能无需任何处理即可继续支持
  • 自行实现 表示此功能已消失,但仅需要一两行代码即可补回功能
  • 丢失 表示此功能已消失,如需实现需要编写大量代码

另外,以上表格仅针对鼠标操作窗口。如果算上使用触摸来操作窗口,那么所有标记为 自行实现 的都将变为 丢失。因为虽然你可以一句话补回功能,但在触摸操作下各种 Bug,你解不完……

  • WPF 程序无法触摸操作?我们一起来找原因和解决方法!

这两种实现的窗口之间还有一些功能上的区别:

方案WindowChromeAllowsTransparency说明
点击穿透在完全透明的部分点击依然点在自己的窗口上在完全透明的部分点击会穿透到下面的其他窗口感谢 nocanstillbb (huang bin bin) 提供的信息

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • 在 WPF 中获取一个依赖对象的所有依赖项属性
  • 如何在 WPF 中获取所有已经显式赋过值的依赖项属性
  • .NET 设计一套高性能的弱事件机制
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地定义和使用弱事件
  • WPF 程序如何跨窗口/跨进程设置控件焦点
  • 使用 SetParent 制作父子窗口的时候,如何设置子窗口的窗口样式以避免抢走父窗口的焦点
  • WPF 程序如何移动焦点到其他控件
  • EFI 分区/恢复分区不可删除?你需要使用命令行了(配合鼠标操作)
  • EFI 分区/恢复分区不可删除?你需要使用命令行了(全命令行操作)
  • 使用傲梅分区助手无损合并分区,无损调整分区大小
  • .NET/C# 检测电脑上安装的 .NET Framework 的版本
  • Windows 系统上用 .NET/C# 查找所有窗口,并获得窗口的标题、位置、尺寸、最小化、可见性等各种状态
  • 直击本质:WPF 框架是如何实现模态窗口的
  • 什么是模态窗口?本文带你了解模态窗口的本质
  • 2017届校招提前批面试回顾
  • Android优雅地处理按钮重复点击
  • ES6--对象的扩展
  • node.js
  • Python 反序列化安全问题(二)
  • SegmentFault 2015 Top Rank
  • vue-cli在webpack的配置文件探究
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 分享一份非常强势的Android面试题
  • 力扣(LeetCode)22
  • 详解NodeJs流之一
  • 详解移动APP与web APP的区别
  • 小程序测试方案初探
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 怎么把视频里的音乐提取出来
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • # 飞书APP集成平台-数字化落地
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (HAL)STM32F103C6T8——软件模拟I2C驱动0.96寸OLED屏幕
  • (二)fiber的基本认识
  • (附源码)ssm学生管理系统 毕业设计 141543
  • (原創) 是否该学PetShop将Model和BLL分开? (.NET) (N-Tier) (PetShop) (OO)
  • (转)大型网站的系统架构
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET MVC第五章、模型绑定获取表单数据
  • .NET程序员迈向卓越的必由之路
  • .NET框架类在ASP.NET中的使用(2) ——QA
  • .NET项目中存在多个web.config文件时的加载顺序
  • .pyc文件还原.py文件_Python什么情况下会生成pyc文件?
  • ??在JSP中,java和JavaScript如何交互?
  • @Autowired注解的实现原理
  • [ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例
  • [Android View] 可绘制形状 (Shape Xml)
  • [AutoSar]BSW_Memory_Stack_003 NVM与APP的显式和隐式同步
  • [C#]获取指定文件夹下的所有文件名(递归)
  • [codevs1288] 埃及分数
  • [JavaWeb学习] Spring Ioc和DI概念思想