title author date CreateTime categories
WPF 使用 Composition API 做高性能渲染
lindexi
2019-07-03 10:30:57 +0800
2019-3-28 10:8:52 +0800
WPF 渲染

在 WPF 中很多小伙伴都会遇到渲染性能的问题,虽然 WPF 的渲染可以甩浏览器渲染几条街,但是还是支持不了游戏级的渲染。在 WPF 使用的 DX 只是优化等级为 9 和 DX 9 差不多的性能,微软在很多开发者的提议开放了现代渲染方法 Composition API 这是 UI 应用的里程碑的技术

现在这个技术只是最小可用版本,但是还是可以玩一下。

先更新自己的系统到1803或以上,如果是想成为 Windows 开发者,就需要自己的系统是最新的

然后下载安装 VS 2019 最新版本,安装 .NET Core 3.0 预览版

官方下载链接 VisualStudio 2019 .NET Core

下载运行代码

github 官方 https://github.com/Microsoft/Windows.UI.Composition-Win32-Samples 下载最新代码,尝试编译运行

打开 dotnet\WPF\HelloComposition 里面的解决方案,注意使用 VisualStudio 2019 打开

通过 Nuget 还原两个库,一个是 Microsoft.Windows.SDK.Contracts 这是一个包含在桌面使用的 Windows Runtime API 库和System.Numerics.Vectors 支持向量计算

这里的 HelloComposition 就是最简单的项目,可以通过这个项目了解使用方法

因为这个项目现在还是预览的,要做好使用命令行编译,在一开始发现了这个项目使用的是以前的 csproj 格式,同时也没法直接在 VisualStudio 2019 里面编译成功,于是我将这个项目格式修改为新的格式,通过命令行还原编译之后就可以在 VisualStudio 2019 调试了。

修改方法是使用下面代码替换 HelloComposition.csproj 文件,同时删除 HelloComposition\Properties\AssemblyInfo.cs 文件

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.SDK.Contracts">
<Version>10.0.17763.144-preview</Version>
</PackageReference>
<PackageReference Include="System.Numerics.Vectors">
<Version>4.5.0</Version>
</PackageReference>
</ItemGroup>
</Project>

如果不想自己修改 csproj 文件可以下载我的修改的版本,先通过命令行还原编译

// 先进入 HelloComposition.sln 所在的文件夹
dotnet restore
// 还原可能失败,如果发现还原失败可以使用 [我收集的各种公有 NuGet 源](https://walterlv.com/post/public-nuget-sources.html )
dotnet build

如果编译成功,那么就可以在 VisualStudio 2019 点击运行调试。如果编译失败,欢迎加入dotnet 职业技术学院交流

运行可以看到下面图片

项目主要代码

那么代码是如何写的?

可以看到主要的代码是 CompositionHostControl 这是一个很普通的 UserControl 控件,在这个控件的 Load 的时候,将自己的内容,也就是一个叫 CompositionHostElement 的 Border 的内容修改为 CompositionHost 的方法

这里的 CompositionHost 是一个自定义的 HwndHost 方法,通过 HwndHost 可以指定为 Host 一个句柄,通过这个方法让 WPF 使用两个不同的渲染方法。

在 CompositionHost 创建了一个新的窗口,然后将这个窗口使用 HwndHost 显示在 WPF 窗口之上,也就是使用 CompositionHost 的控件将会显示在其他任何 WPF 控件的上面,也就是在 CompositionHost 控件的 Bounds 范围内,是不能使用其他的 WPF 控件的。这和在 WPF 中使用其他渲染方法的窗口一样,这个技术也是在 WPF 中使用 WinForms 或 UWP 控件的技术

在 CompositionHost 的主要代码是 InitComposition 方法,在这里创建了 Composition 通过黑科技的方法,感觉这里的代码将会写在一个框架里面,同时也不是很清真,更大的原因是我也不了解这个黑科技是什么,所以就跳过了。

在跳过这个类,其他的代码是非常容易的,可以看到方法的接口和 UWP 的一样,在 CompositionHostControl_Loaded 方法返回了 Compositor 的字段,对他的使用就和 UWP 的使用一样

        private void CompositionHostControl_Loaded(object sender, RoutedEventArgs e)
{
// If the user changes the DPI scale setting for the screen the app is on,
// the CompositionHostControl is reloaded. Don't redo this set up if it's
// already been done.
if (compositionHost is null)
{
currentDpi = VisualTreeHelper.GetDpi(this); compositionHost = new CompositionHost(CompositionHostElement.ActualHeight, CompositionHostElement.ActualWidth);
// 手动高亮,下面的代码就是将 CompositionHostElement 这个 Border 的内容修改为 CompositionHost 这个 HwndHost 通过 Host 一个窗口的方法
CompositionHostElement.Child = compositionHost; // 手动高亮,下面的代码返回 Compositor 字段
compositor = compositionHost.Compositor;
// 手动高亮,下面的代码返回 ContainerVisual 字段
containerVisual = compositor.CreateContainerVisual();
compositionHost.Child = containerVisual;
}
}

在点击按钮的时候就创建一个 SpriteVisual 加入到 ContainerVisual 里面,然后做 Vector3KeyFrameAnimation 动画

这里面的代码接口和 UWP 相同,就不详细告诉大家如何使用

用到的黑科技

通过 HwndHost 方法拿到一个窗口的句柄

其实不是直接在 WPF 使用 Composition 而是在创建一个窗口使用 Composition 因为 WPF 的渲染和 Composition 的不相同

也是因为使用了这个技术,所以会存在一些坑,将会在本文下面告诉大家

通过 COM 等方法调用额外的系统相关的接口

如果只是创建一个空白的窗口是没法直接用到 Composition API 需要使用一些黑科技,这些代码都在 CompositionHost 因为我也看不懂,所以就跳过

如果想不开请看 Using the Visual Layer with WPF

将 Visual Layer 的内容封装在 WPF 的用户控件

在 CompositionHostControl 这个用户控件,使用的封装的 Visual Layer 在里面的代码和 UWP 的相同

如何使用可以看 UWP 的 Visual Layer documentation

预览代码

主要用到类有三个

CompositionHost

连接 WPF 的渲染和 UWP 的 Visual Layer 也是这个呆魔的主要代码

官方建议是直接复制这个类里面的代码,在 Create an HwndHost derived class to host composition elements 也只是告诉大家如何写

CompositionHostControl

使用封装之后的方法,简单告诉大家如何添加 Visual 和动画

最后一个文件是主窗口,里面也就是放了一个按钮和 CompositionHostControl 代码很简单

不足

虽然可以在 WPF 用 Composition API 做出好看界面,但是因为主要技术是通过 HwndHost 方法,这个方法也还没有正式使用,存在下面的不足

  • 特效依赖于 Win2d 但是现在 win2d 还没有支持桌面的 Nuget 库,需要编译源代码 不过很快就可以直接通过 Nuget 的方法

  • 如果需要交互命中测试需要在代码计算 Visual Layer 的 Bounds 没有和在 UWP 通过 xaml 的方法简单绑定对应的命中测试,不过很快也就有封装的方法

  • 现在的 Visual Layer 还没有支持渲染文本,但是可以通过 SharpDX 的方法渲染,很快就可以原生支持

  • 因为是 Host 的技术,不能自动在 DPI 修改的时候缩放,需要写很多代码适配

  • 如果说上面几个坑都还是可以解决的,那么下面的坑就是原理的问题。因为使用了 HwndHost 用了两个渲染方法,在使用 UWP 渲染方法的范围会在窗口的最上也就是 WPF 无法在这个范围放任何的像素,同时也存在焦点等问题

Using the Visual Layer with WPF

Visual Layer documentation

Windows.UI.Composition Namespace

我收集的各种公有 NuGet 源

我修改的代码

官方代码

特别感谢

  • 蓝火火 告诉我通过 COM 方法不是通过 PInvoke 调用系统

2019-7-3-WPF-使用-Composition-API-做高性能渲染的更多相关文章

  1. WPF 使用 Composition API 做高性能渲染

    在 WPF 中很多小伙伴都会遇到渲染性能的问题,虽然 WPF 的渲染可以甩浏览器渲染几条街,但是还是支持不了游戏级的渲染.在 WPF 使用的 DX 只是优化等级为 9 和 DX 9 差不多的性能,微软 ...

  2. Vue 3.0 Composition API - 中文翻译

    Composition API 发布转载请附原文链接 https://www.cnblogs.com/zgh-blog/articles/composition_api.html 这两天初步了解了下 ...

  3. UWP Composition API - 锁定列的FlexGrid

    需求是第一列锁定,那么怎么让锁定列不跟着滚动条向做移动呢? 其实很简单,让锁定列跟scrollviewer的滚动做反方向移动. 先看一下这个控件的模板,嗯,其实很简单,就是ListView的模板,不同 ...

  4. UWP Composition API - GroupListView(二)

    还是先上效果图: 看完了上一篇UWP Composition API - GroupListView(一)的童鞋会问,这不是跟上一篇一样的吗??? 骗点击的?? No,No,其实相对上一个有更简单粗暴 ...

  5. UWP Composition API - GroupListView(一)

    需求: 光看标题大家肯定不知道是什么东西,先上效果图: 这不就是ListView的Group效果吗?? 看上去是的.但是请听完需求.1.Group中的集合需要支持增量加载ISupportIncreme ...

  6. UWP Composition API - PullToRefresh

    背景: 之前用ScrollViewer 来做过 PullToRefresh的控件,在项目一些特殊的条件下总有一些问题,比如ScrollViewer不会及时到达指定位置.于是便有了使用Compositi ...

  7. [UWP小白日记-12]使用新的Composition API来实现控件的阴影

    前言 看了好久官方的Windows UI Dev Labs示例好久才有点心得,真是头大.(其实是英语幼儿园水平(⊙﹏⊙)b) 真的网上关于这个API的资料可以说几乎没有. 正文 首先用这东西的添加WI ...

  8. UWP Composition API - New FlexGrid 锁定行列

    如果之前看了 UWP Jenkins + NuGet + MSBuild 手把手教你做自动UWP Build 和 App store包 这篇的童鞋,针对VS2017,需要对应更新一下配置,需要的童鞋点 ...

  9. UWP Composition API - RadialMenu

    用Windows 8.1的童鞋应该知道OneNote里面有一个RadialMenu.如下图,下图是WIn10应用Drawboard PDF的RadialMenu,Win8.1的机器不好找了.哈哈,由于 ...

  10. Windows Composition API 指南 - 认识 Composition API

    微软在 Windows 10中 面向通用 Windows 应用 (Universal Windows Apps, UWA) 新引入了一套用于用户界面合成的 API:Composition API.Co ...

随机推荐

  1. 前端面试题之一JAVASCRIPT(理论类)

    一.请描述一下 cookies.sessionstorage .localstorage 和session的区别?(1)cookie是网站为了标示用户身份而储存在用户本地终端(client side) ...

  2. Mui本地打包笔记(一)使用AndroidStudio运行项目 转载 https://blog.csdn.net/baidu_32377671/article/details/79632411

    转载 https://blog.csdn.net/baidu_32377671/article/details/79632411 使用AndroidStudio运行HBuilder本地打包的Mui项目 ...

  3. 组件:基础的基础组件(Component,Portlet)

    <!DOCTYPE html> <html lang="zh"> <head> <title></title> < ...

  4. day 42 01--CSS的引入方式及CSS选择器

    01--CSS的引入方式及CSS选择器   本节目录 一 CSS介绍 二 行内样式 三 内接样式 四 外接样式 五 CSS的选择器 六 CSS的高级选择器 七 CSS的属性选择器 八 CSS的伪类选择 ...

  5. PAT甲级——A1094 The Largest Generation

    A family hierarchy is usually presented by a pedigree tree where all the nodes on the same level bel ...

  6. gethostname gethostbyname gethostbyaddr 获得主机相关信息

    网络编程里经常需要获得主机的相关信息,下面围绕相关的函数以及用到的结构来说明. 获得主机名:int gethostname( char FAR *name, //[out] Pointer to a ...

  7. There is no public key available for the following key IDs:3B4FE6ACC0B21F32

    ubuntu 运行完sudo apt-get update之后,提示 W: There is no public key available for the following key IDs: 3B ...

  8. spring boot项目搭建中遇到的问题

    自己动手搭建一下spring boot的项目,中途遇到了几个问题,在这里记录一下! 一.关于数据库中的表设计的问题 1.设计表的时候一定要添加的两个字段created updated 创建时间与更新时 ...

  9. noi.openjudge 二分法求函数的零点

    二分法求函数的零点 总时间限制: 1000ms 内存限制: 65536kB 描述 有函数:f(x) = x5 - 15 * x4+ 85 * x3- 225 * x2+ 274 * x - 121 已 ...

  10. poj 3263

    传送门 解题思路 如果x与y互相看见,那么他们一定比之间的高,所以给他们之间的高度-1,最后得到的答案是所有牛的高度+h,之间-1会T,用差分数组或线段树维护即可. 代码 #include<io ...