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


    26 篇文章3 订阅

    背景透明的异形窗口

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

    示例异形窗口

    此窗口包含很大的圆角,还包含 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" 会造成很严重的性能问题。

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

    性能对比

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

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

    测试性能所用的程序

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

        <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 为最好 59 19
    脏区刷新率(rects/s)数值越大越好 117 38
    显存占用(MB)数值越小越好 83.31 193.29
    帧间目标渲染数(个)数值越大越好 2 1

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

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

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

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

    此性能差异的原理解读,请参阅:

    功能对比

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

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

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

    表格中:

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

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

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

    方案WindowChromeAllowsTransparency
    点击穿透 在完全透明的部分点击依然点在自己的窗口上 在完全透明的部分点击会穿透到下面的其他窗口

    然而,如果你希望在使用高性能的 WindowChrome 时也依然能点击穿透,那么你需要使用到一点点的小技巧来绕过 WPF 对 WS_EX_LAYERED 窗口样式的锁定。请参见:WPF 制作支持点击穿透的高性能的透明背景异形窗口

    本文会经常更新,请阅读原文: https://blog.walterlv.com/post/wpf-transparent-window-without-allows-transparency.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

  • 相关阅读:
    Idea 代码编辑错误不飘红提示
    Java序列化机制和原理
    tomcat 启动报错org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalin
    idea tomcat 怎样出现update classes and resources
    Java List序列化的实现
    Spring管理的bean初始化方法的三种方式,以及@PostConstruct不起作用的原因
    Tomcat 启动或者发布项目时提示Publishing failed:Resource /xxxx does not exist
    spring中的context:include-filter和context:exclude-filter的区别
    oracle字符集修改
    VML、SVG、Canvas简介
  • 原文地址:https://www.cnblogs.com/webenh/p/16168951.html
Copyright © 2020-2023  润新知