本文将和大家介绍如何将 Microsoft.Maui.Graphics 对接到 UNO 框架里面。一旦完成 Microsoft.Maui.Graphics 对接,即可让 UNO 框架复用现有的许多绘制的基础设施和现有基础库,且可以更进一步与 MAUI 打通
众所周知,在 UNO 里面有大量的项目类型都是基于 Skia 作为底层渲染引擎构建出来的。在 Microsoft.Maui.Graphics 中有对 Skia 的一个实现,即 Microsoft.Maui.Graphics.Skia 实现方式。根据 UNO 的 Skia 例子 可以知道,在 UNO 里面是可以采用 SKXamlCanvas 执行直接对 Skia 绘制的内容的
然而坏消息是当前在 2024.01.29 时,在 UNO 里面的 SKXamlCanvas 是采用一个 Hack 的方式与 UNO 对接。在 SKXamlCanvas 里面将会重新创建 SKSurface 用于让开发者在此之上绘制,接着再将绘制的 Bitmap 通过 CPU 拷贝到 UNO 的 WriteableBitmap 上,让 UNO 使用图片绘制的形式将 WriteableBitmap 绘制出来。通过 WriteableBitmap 与 Skia 进行间接对接的方式,将会极大影响绘制性能,在绘制的中间存在很大的 CPU 压力和绘制延迟。此问题的讨论地址: https://github.com/unoplatform/uno/discussions/15097
为了减少 SKXamlCanvas 的 Hack 方式的影响,本文这里采用了 UNO 框架里面未公开的 Visual 绘制方式。由于本方式用到的是 UNO 框架私有的 API 实现的功能,因此可能在后续的 UNO 更新版本,本文提供的方法将会无效
本文不是提供一个开箱即用的方法,代替的是,本文提供的是一套源代码搭建对接的方法。阅读完成本文,你将学会如何自行在自己的 UNO 项目里面搭建与 Microsoft.Maui.Graphics 对接的代码,且了解其中的细节实现逻辑,方便你进行更进一步的定制。在本文末尾你将找到本文用到的所有代码的下载方法
本文以下提供了在 Uno.Skia.WPF 和 Uno.Skia.GTK 平台下,使用与 UNO 的 Visual 直接对接的方式,而不是经过了 WriteableBitmap 的 SKXamlCanvas 方式,进行与 Microsoft.Maui.Graphics.Skia 对接,进而将 Microsoft.Maui.Graphics 对接到 UNO 框架
整体的架构引用关系图如下
上图的 Microsoft.Maui.Graphics.UnoAbstract 和 UnoHacker (SamplesApp) 就是接下来咱重点要工作的部分,额外的一部分工作则放在 Uno.Skia.WPF 和 Uno.Skia.GTK 平台对接代码上,平台项目的对接工作量很小,所需的代码量很少
先从 Microsoft.Maui.Graphics.UnoAbstract 项目的搭建开始,在 Microsoft.Maui.Graphics.UnoAbstract 项目里面提供了一些用于 UnoHacker (SamplesApp) 使用的 Hack 接口,用于方便上层应用框架对接,其定义的代码如下
通过以上的代码,即可在 HackHelper 里面注入 Hack 对象的值。另外的,为了获取到绘图的通知,即与 FrameworkElement 的更特殊的实现,这里也需要在 Microsoft.Maui.Graphics.UnoAbstract 项目里面添加名为 IDrawableNotify 的接口,代码如下
完成基础的接口定义之后,即可在 Microsoft.Maui.Graphics.UnoAbstract 项目编写用于给通用跨平台的 UNO 业务项目直接使用的 GraphicsCanvas 类型。此 GraphicsCanvas 类型将继承 Microsoft.UI.Xaml.Controls.Canvas 类型,可以直接在 XAML 里面加入,且在开始绘制时触发 Draw 事件,方便业务代码使用 Draw 事件编写 Microsoft.Maui.Graphics 的绘制业务代码
接下来创建 UnoHacker (SamplesApp) 项目,这个项目需要设置项目的程序集名为 SamplesApp
才可以使用到 UNO 框架里面的一些内部成员,方便起见可以将此项目直接命名为 SamplesApp 项目。之所以叫这个名字是因为在 UNO 里面添加了 Internal 对名为 SamplesApp
程序集可见
再次说明,由于 UnoHacker (SamplesApp) 项目将使用 UNO 的一些不公开的类型,可能在后续的 UNO 版本里将会失效
在 UnoHacker (SamplesApp) 项目里面只需一个简单的类型,此类型将与 UNO 的 Visual 进行对接,代码如下
如此就完成了与 Microsoft.Maui.Graphics 对接的基础代码了,剩余的工作就需要在具体的 Uno.Skia 平台项目里面编写对接代码,通过在 Uno.Skia 平台项目里面编写对接代码将 Microsoft.Maui.Graphics.UnoAbstract 与 UnoHacker (SamplesApp) 项目进行对接。额外说明的是为什么不能将 Microsoft.Maui.Graphics.UnoAbstract 与 UnoHacker (SamplesApp) 项目合并,原因是为了让 Microsoft.Maui.Graphics.UnoAbstract 项目还可以在 UNO 的非 Skia 实现平台上使用,只让 UnoHacker (SamplesApp) 项目强引用 UNO 的 Skia 实现,如此即可让 Microsoft.Maui.Graphics.UnoAbstract 项目同时被 UNO 的 WinUI3 等非 Skia 的实现的项目进行对接
接下来开始编写 Uno.Skia.WPF 和 Uno.Skia.GTK 平台对接代码,这两个部分的平台对接代码内容都是相同的。先定义一个名为 HackElement 的继承 GraphicsCanvasElement 的控件,代码如下,定义此类型控件仅仅只是为了方便统一对接代码而已
接着创建名为 Hack
的类型,让此类型继承 Microsoft.Maui.Graphics.UnoAbstract 的 IHack 接口,代码如下
最后创建 HackInitializer 类型,用于将 Hack 类型放入到 Microsoft.Maui.Graphics.UnoAbstract 的 HackHelper 静态类型里面
通过以上的封装代码,即可在各平台项目里面通过调用 HackInitializer 的 Init 方法,即可完成所有的对接逻辑。比如在 Uno.Skia.Wpf 的默认 App 构造函数里面,调用 HackInitializer.Init();
代码。比如在 Uno.Skia.GTK 项目里面的 Program 里面,使用如下面代码调用对接方法
完成所有对接逻辑之后,接下来即可在 UNO 的全平台项目里面,使用 GraphicsCanvas 绘制业务代码的界面。比如在 MainPage.xaml 里面添加以下代码
在后台代码即可在 GraphicsCanvas_OnDraw
方法的 Microsoft.Maui.Graphics.ICanvas 参数里面获取到与整个 Microsoft.Maui.Graphics 对接的开始,如下面代码简单绘制界面
运行项目,将可以看到如下界面
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码
获取代码之后,进入 KefalurcilaybelJallbuderenajel 文件夹
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。 欢迎转载、使用、重新发布,但务必保留文章署名 林德熙 (包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我 联系。