2019-7-3-WPF-使用-Win2d-渲染
| title | author | date | CreateTime | categories |
|---|---|---|---|---|
|
WPF 使用 Win2d 渲染
|
lindexi
|
2019-07-03 16:27:59 +0800
|
2019-7-3 10:31:2 +0800
|
WPF win2d
|
在当前所有渲染框架里面,做 2D 渲染的,最好的框架是 Win2d 这个提供了大量底层接口封装,不仅性能高同时接口设计非常好
在很久之前,只有在 UWP 等现代应用才能使用 Win2d 而 WPF 是不能使用的。好在微软开放了一些黑科技,可以在 WPF 上使用 Win2d 渲染,下面就让我告诉大家如何在 WPF 上使用
在 2019年7月03日 这个技术还是属于黑科技,还没有正式发布,在开始使用之前,有一定的环境要求
- 需要 VisualStudio 2017 和以上,点击Visual Studio下载链接下载最新的工具
- 需要在 VisualStudio 的开发添加 UWP 和桌面开发
- 需要在设备安装 .NET Framework 4.7.2 及以上,同时新建项目需要选择 .NET Framework 4.7.2 和以上。有小伙伴说 45 也是可以的,但是步骤会更多,建议小伙伴在看完本文测试过了才尝试降级
- 开发和运行设备是 Windows 10 版本 1903 和以上
- 开发设备上安装 UWP 的 SDK 版本是 18362 及以上 Windows 10 SDK - Windows 应用开发
新建一个 WPF 的 .NET Framework 4.8 项目,在这个项目上面安装下面 NuGet 包
- Microsoft.Windows.SDK.Contracts
- Microsoft.VCRTForwarders.140
- System.Numerics.Vectors
- Win2D.uwp
如果有安装不上的,例如有下面提示
无法安装程序包“Win2D.uwp 1.23.0”。你正在尝试将此程序包安装到目标为“.NETFramework,Version=v4.8”的项目中,但该程序包不包含任何与该框架兼容的程序集引用或内容文件。有关详细信息,请联系程序包作者。
右击编辑 csproj 文件,在 csproj 文件里面添加下面代码。注意此时你新建的项目使用的 nuget 格式需要新的 Nuget 格式,也就是不带 package.config 文件的格式
<PackageReference Include="Microsoft.VCRTForwarders.140">
<Version>1.0.0-rc</Version>
</PackageReference>
<PackageReference Include="Microsoft.Windows.SDK.Contracts">
<Version>10.0.18362.2002-preview</Version>
</PackageReference>
<PackageReference Include="System.Numerics.Vectors">
<Version>4.5.0</Version>
</PackageReference>
<PackageReference Include="Win2D.uwp">
<Version>1.22.0</Version>
</PackageReference>
这样就可以强制安装
准备好了环境和 NuGet 之后就可以开始开发了
和之前博客 WPF 使用 Composition API 做高性能渲染 所说方法搭建代码
搭建出 CompositionHost 和 CompositionHostControl 两个类,然后在 CompositionHostControl 里面添加 Win2d 相关方法
在 CompositionHostControl 的构造函数给 Win2d 初始化
private readonly CanvasDevice _canvasDevice;
public CompositionHostControl()
{
InitializeComponent();
// 手动高亮,下面代码用于创建 Win2d 的渲染设备
_canvasDevice = CanvasDevice.GetSharedDevice();
// 忽略其他代码
}
以上忽略代码可以在 Windows.UI.Composition-Win32-Samples 找到
在 CompositionHostControl_Loaded 事件里面才是核心代码
想要让 Win2d 绘制在界面上,需要在界面存放一张平面,让 Win2d 在这个平面上绘制,然后将平面加入到渲染的平面列表里面,这样就可以进行渲染了
// 创建链接 _compositor 和 _canvasDevice 的链接
_compositionGraphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(_compositor, _canvasDevice); // 创建一个平面,将会让 Win2d 在这个平面渲染
var noiseDrawingSurface = _compositionGraphicsDevice.CreateDrawingSurface(
new Windows.Foundation.Size(_rectWidth, _rectHeight),
DirectXPixelFormat.B8G8R8A8UIntNormalized,
DirectXAlphaMode.Premultiplied);
// 忽略一些代码 // 在这个函数里面就是让 Win2d 绘制的方法,其实在我自己的项目里面没有用到 noiseFilePath 变量
LoadSurface(noiseDrawingSurface, noiseFilePath); // 在 Win2d 渲染到平面完成之后,将这个平面作为一个画刷用于在之后的效果
_noiseSurfaceBrush = _compositor.CreateSurfaceBrush(noiseDrawingSurface);
在 LoadSurface 方法里面进行绘制,请看创建代码
void LoadSurface(CompositionDrawingSurface surface, string path)
{
// Draw to surface.
using (var ds = CanvasComposition.CreateDrawingSession(surface))
{
ds.Clear(Colors.Transparent); var rect = new Windows.Foundation.Rect(0, 0, _rectWidth, _rectHeight);
ds.FillRectangle(rect, Colors.Coral);
}
}
这样就可以将 Win2d 的内容渲染到一个平面上,然后将这个平面作为画刷,在微软的代码里面是将这个画刷作为亚克力的画刷,然后将亚克力放在内容里面
下面是简化的代码
LoadSurface(noiseDrawingSurface, noiseFilePath);
var visual = _compositor.CreateSpriteVisual();
// 忽略 visual 的参数设置
_acrylicVisual = visual;
// 创建亚克力画刷
_acrylicVisual.Brush = CreateAcrylicEffectBrush(); // 加入到图层
_containerVisual.Children.InsertAtTop(_acrylicVisual);
现在就完成了在 WPF 里面使用 Win2d 顺便还提供了亚克力的功能
其实本文主要不是告诉大家如何写代码,而是如何让官方的代码可以运行
在运行过程可能会遇到以下的坑
如在开始编译的时候提示下面代码
C:\Users\lindexi.github.io\.nuget\packages\win2d.uwp\1.23.0\build\Win2D.common.targets(37,5): Error: This version of Win2D requires Windows SDK >= 10.0.17134.0, but TargetPlatformVersion is 7.0.
主要原因是现在 Microsoft.Windows.SDK.Contracts 只能让 Win2d 的 1.22 版本运行,解决方案是将原本的 1.23 版本降级到 1.22 版本
在运行过程,运行到 _canvasDevice = CanvasDevice.GetSharedDevice() 的时候提示下面的代码
System.TypeLoadException:“所请求的 Windows 运行时类型“Microsoft.Graphics.Canvas.CanvasDevice”未注册。”
这个问题是因为没有在 app.manifest 文件里面添加下面代码
<file name="Microsoft.Graphics.Canvas.dll">
<activatableClass
name="Microsoft.Graphics.Canvas.CanvasDevice"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1"/> <activatableClass name="Microsoft.Graphics.Canvas.UI.Composition.CanvasComposition"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1"/> <activatableClass
name="Microsoft.Graphics.Canvas.Effects.SaturationEffect"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1"/> <activatableClass
name="Microsoft.Graphics.Canvas.Effects.BlendEffect"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1"/> <activatableClass
name="Microsoft.Graphics.Canvas.Effects.GaussianBlurEffect"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1"/> <activatableClass
name="Microsoft.Graphics.Canvas.Effects.ColorSourceEffect"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1"/> <activatableClass
name="Microsoft.Graphics.Canvas.Effects.CompositeEffect"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1"/> <activatableClass
name="Microsoft.Graphics.Canvas.Effects.OpacityEffect"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1"/> <activatableClass
name="Microsoft.Graphics.Canvas.CanvasBitmap"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1"/>
<activatableClass
name="Microsoft.Graphics.Canvas.Effects.BorderEffect"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1"/>
</file>
或者这个文件没有在 csproj 声明,也就是没有在项目文件找到下面代码
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
在运行的时候,还是在 _canvasDevice = CanvasDevice.GetSharedDevice() 提示下面的代码
System.IO.FileNotFoundException:“找不到指定的模块。 (异常来自 HRESULT:0x8007007E)”
这个问题是在输出文件夹缺少文件,请确定当前使用的是 x64 的设备,同时进行 AnyCpu 编译,没有勾选首选 32 的程序
然后确定在 bin\debug 文件夹里面是否存在以下文件
- vcruntime140_app.dll
- msvcp140_app.dll
- Microsoft.Graphics.Canvas.dll
- System.Numerics.Vectors.dll
- Microsoft.Graphics.Canvas.winmd
在安装 Microsoft.VCRTForwarders.140 默认就会创建前面两个文件,在进行x64编译的时候。如果使用的是 AnyCpu 编译,那么就需要手动拷贝文件
而 Microsoft.Graphics.Canvas.dll 文件是需要手动拷贝的
手动复制文件的方法是打开自己的本地 .nuget 源,在 c:\Users\用户名\.nuget\packages\ 里面可以找到
如我的 Microsoft.VCRTForwarders.140 内容在 c:\Users\lindexi.github.io\.nuget\packages\microsoft.vcrtforwarders.140\1.0.0-rc\runtimes\win10-x64\native\release\ 文件,将里面的文件复制到输出文件夹
打开 c:\Users\lindexi.github.io\.nuget\packages\win2d.uwp\1.22.0\runtimes\win10-x64\native\ 将 Microsoft.Graphics.Canvas.dll 文件复制到输出文件夹
请将上面文件夹的用户名替换为你自己的用户名
当然这样的呆魔大家一定不想使用,于是我将需要添加的文件放在项目文件,设置自动输出,请小伙伴换我的项目试试
我将代码放在 Github 只需要下载代码,然后打开 sln 文件,右击还原项目,然后在 AnyCpu 下按下运行就可以
2019-7-3-WPF-使用-Win2d-渲染的更多相关文章
- dotnet 读 WPF 源代码笔记 渲染收集是如何触发
在 WPF 里面,渲染可以从架构上划分为两层.上层是 WPF 框架的 OnRender 之类的函数,作用是收集应用程序渲染的命令.上层将收集到的应用程序绘制渲染的命令传给下层,下层是 WPF 的 GF ...
- 2019-11-29-WPF-使用-Win2d-渲染
原文:2019-11-29-WPF-使用-Win2d-渲染 title author date CreateTime categories WPF 使用 Win2d 渲染 lindexi 2019-1 ...
- WPF 渲染级别 (Tier)
在WPF中,显卡的功能相差很大.当WPF评估显卡时,它会考虑许多因素,包括显卡上的RAM数量.对像素着色器(piexl shader)的支持(计算每个像素效果的内置程序,如透明效果),以及对顶点着色器 ...
- WPF 渲染原理
原文:WPF 渲染原理 在 WPF 最主要的就是渲染,因为 WPF 是一个界面框架.想用一篇博客就能告诉大家完整的 WPF 渲染原理是不可能的.本文告诉大家 WPF 从开发者告诉如何画图像到在屏幕显示 ...
- WPF 使用 SharpDx 异步渲染
本文告诉大家如何通过 SharpDx 进行异步渲染,但是因为在 WPF 是需要使用 D3DImage 画出来,所以渲染只是画出图片,最后的显示还是需要 WPF 在他自己的主线程渲染 本文是一个系列,希 ...
- WPF 设置纯软件渲染
最近看到有小伙伴说 WPF 使用硬件渲染,如何让 WPF 不使用硬件渲染,因为他觉得性能太好了.万一这个版本发布了,产品经理说下个版本要提升性能就不好了.于是就找到一个快速的方法,让程序不使用硬件渲染 ...
- dotnet 读 WPF 源代码笔记 布局时 Arrange 如何影响元素渲染坐标
大家是否好奇,在 WPF 里面,对 UIElement 重写 OnRender 方法进行渲染的内容,是如何受到上层容器控件的布局而进行坐标偏移.如有两个放入到 StackPanel 的自定义 UIEl ...
- WPF 使用 Silk.NET 进行 DirectX 渲染入门
本文告诉大家如何使用 dotnet 基金会新开源的 Silk.NET 库调用 DirectX 进行渲染的方法.此库是对 DirectX 的底层基础封装,用上了 dotnet 和 C# 的各个新特性,相 ...
- 用 UI 多线程处理 WPF 大量渲染的解决方案
众所周知, WPF 的 UI 渲染是单线程的,所以如果我们异步或者新建线程去进行数据处理的时候,处理完,想要更新 UI 的时候,需要调用一下 Dispatcher.Invoke,将处理完的数据推入到 ...
随机推荐
- jmeter 中使用正则表达式提取依赖参数
1:登录接口 这里有一个实际的登录接口,在响应中返回了一串token,如下图 那么我们在接下来的接口-经验库列表中,就必须带入这一串token,否则响应报错,如下图所示 如何获取登录的口令呢?这 ...
- 改变JAVA窗体属性的操作方法
在本篇内容里小编给大家详细分析了关于改变JAVA窗体属性的操作方法和步骤,需要的朋友们学习下. 若将JDK版本升级到最新版本,Java窗体就可以简单实现窗体的透明效果,用户可以通过拉动滑块(Slide ...
- 史诗级最强教科书式“NIO与Netty编程”
史诗级最强教科书式“NIO与Netty编程” 1.1 概述 1.2 文件IO 1.2.1 概述和核心API 1.2.2 案例 1.3 网络IO 1.3.1 概述和核心API 3.4 AIO编程 3.5 ...
- C#基本语法<二>_线程
线程 多线程和异步函数 当异步线程在工作完成时如何通知调用线程 当异步线程出现异常的时候该如何处理 异步线程工作的进度如何实时的通知调用线程 如何在调用线程中取消正在工作的异步线程,并进行回滚操作 异 ...
- PostgreSQL 表字段起别名
使用Postgreq Sql 表字段起别名时注意要用双引号,使用单引号会出现语法错误,执行结果如图
- Vue.js+vue-element搭建属于自己的后台管理模板:更深入了解Vue.js(三)
前言 上一章我们介绍了关于Vue实例中一些基本用法,但是组件.自定义指令.Render函数这些放到了本章来介绍,原因是它们要比前面讲的要难一些,组件是Vue.js最核心的功能,学习使用组件也是必不可少 ...
- opencv-python 图像基础处理(三)
腐蚀操作 #腐蚀操作 import cv2 import numpy as np img=cv2.imread("d:/ke.png") kernel = np.ones((3,3 ...
- 【Gradle】Groovy基础
Groovy基础 Groovy是基于JVM虚拟机的一种动态语言.每个Gradle的build脚本文件都是一个Groovy脚本文件. 字符串 在Groovy中,分号不是必需的.在Groovy中,单引号和 ...
- MySQL数据库:在命令提示符中使用mysql
服务启动 在命令提示符中 启动mysql服务 net start mysql 停止mysql服务 net sotp mysql 通过命令行进入 mysql -u 用户名 -p 键入后会提示输入密码 如 ...
- Jenkins实现单一安卓项目打包多个module填坑实录
今天接手一个任务,已有项目结构上新添加了一个module,这个module打包工作需要在Jenkins上添加一个方便测试点击的打包工程 因为之前已有现成的打包工程,我直接新建了一个工程并且复制原有工程 ...