WPF 使用 MAUI 的自绘制逻辑

这是一个当前还没开发完成的功能,准确来说连预览版也算不上的功能。我原本以为 MAUI 是无法在 WPF 上面跑的,然而在看完了 MAUI 整个大的设计,才了解到,原来 MAUI 是一个非常庞大的开发项目。在 MAUI 里面,虽然现在是正式发布的,但正式发布的版本里面只有采用原生控件进行绘制的方案。这和官方开始的宣传不符合,在阅读了 MAUI 相关文档才发现,实际上 MAUI 还有一个很大的部分,那就是自绘部分,还没完成,代码也分了仓库,这就是一开始没找到的原因。本文将告诉大家 MAUI 还没发布的这部分大杀器

本文所涉及的全部都是绘制的渲染层,而众所周知,一个 UI 框架最重要的两个部分就是交互和渲染。本文仅仅只会涉及到渲染的一部分

cfc23c0344cabf34f349064f3a5eab74.png

制作一个跨平台的 UI 框架有很多个方式,例如使用各个平台提供的原生控件,也就是说在 Windows 平台上,采用 WinUI 的按钮,在 iOS 平台上使用苹果提供的按钮,具体的按钮样式等等就需要取平台最小集以及开放定制性,最重要的代表就是原先的 Xamarin 的方式。采用各个平台的提供的原生控件的一个优势在于可以获取平台提供的功能,更加贴合具体平台的视觉和交互,缺点是不同的平台的视觉效果有所差异。另一个方式是做中间较底层的自绘,基本上各个平台都会提供自绘的能力,如 WPF 下的 DrawingContext 和 Win2D 等等,基于此方式做自绘,可以更加方便接入原有的平台,降低原有的应用接入的成本,而这就是本文的重点。最后一个方式是做底层的自绘,使用平台最底层的绘制逻辑,或者其他渲染框架的封装进行二次封装,如 Skia 或 GTK 等,对此进行渲染。使用底层的自绘逻辑可以做到更多的可控性,但缺点也在于可控性导致开发起来十分麻烦,与现有的应用接入也相对来说无法实现最好的性能

3ab7c22e74b20c3ea56d3b7175499ede.png

很多的 UI 框架都会采用其中的一个方式。然而别忘了 MAUI 是某软主力做的,按照某软的想法,那就是都要。在 MAUI 里面,既可以使用平台提供的原生控件进行拼接制作界面,也可以使用基于的各个平台的独立 UI 框架提供的自绘能力绘制界面,也可以调用到底层的渲染逻辑进行渲染

但,这也不是免费的。如此大的一个项目,自然投入的成本,无论是人力还是开发周期,都是非常庞大的。尽管现在 MAUI 正式发布了,可惜还有很大部分的工作还没完成,甚至还没开始

在吸取了很多次失败的教训之后,某软决定拆分仓库,以解决如此大的一个项目的某些组件或部分的失败带来整体的失败。这是 dotnet runtime 组的成功的例子带来的组织形式的经验,在 dotnet runtime 里面,将不稳定的实验的功能放在 .NET Runtime Lab 仓库里面。不稳定的功能,如果能成,那自然能大大提升 dotnet 的竞争力,如果不成也不应该影响到整个 dotnet 的发布

当前的 MAUI 也是这个管理方式,在 MAUI 里面,将渲染层拆出一个 Microsoft.Maui.Graphics 仓库,如 MAUI 自定义绘图入门 所提到的。其实 Microsoft.Maui.Graphics 是由原本的 System.Graphics 改名而来。这个 System.Graphics 项目初步完成时间比 MAUI 早很多,定位是做全平台的绘制封装层,提供了各个平台的绘制渲染的上层统一。包括了两个实现方式,一个是对各个平台提供的 UI 框架的自绘逻辑进行封装,从而对上层统一。另一个方式对各个底层绘制渲染逻辑包括 Skia 和 GTK 甚至是 DirectX 进行封装,从而提供给上层统一的逻辑,只需要简单的代码即可切换

ed4fd9c5a2f085a9f61fd514e4a55435.png

接下来是在有 Microsoft.Maui.Graphics 的基础上,也就是在能提供各个平台上层统一的绘制能力之后,进行实现各个基础控件。这就是 Microsoft.Maui.Graphics.Controls 仓库,这个仓库的需求就是制作自绘的控件。如此即可实现各个平台上像素级的统一,或者是更加方便接入原有的应用的 UI 框架

本文是在 2022.06 写的,以上的很多功能都只是能吹不能用。但是只是写一篇水文,那可不是我的风格。自然就是开始实际的写代码阶段

认识我的伙伴们都知道,我对渲染是比较熟悉的。我接下来将告诉大家,如何使用 Maui 提供的框架层,配合 WPF 提供具体的自绘逻辑,两个放在一起,从而实现 WPF 使用 MAUI 的自绘逻辑

08216f0b070742771cb62eac48d5c9f0.png

核心的实现方法是 WPF 提供画布功能,让 MAUI 可以在 WPF 上面画元素。在 MAUI 里面提供框架,以及具体的绘制指导,和上层 API 调用

本文以下部分将用到还没有发布,但是也差不多快完成的 Microsoft.Maui.Graphics.Xaml.WPF 提供的功能。这个库的代码放在 Microsoft.Maui.Graphics 仓库,这个库属于做中间较底层的自绘,利用 WPF 提供的丰富的绘图能力从而介入 MAUI 定义的抽象接口。由于此库还没完成,为了完成接入,我没有使用 DLL 引用,而是拷贝了这个库的代码到我的测试代码里面,然后再进行稍微的魔改,解决构建不通过

大概的对接方式如下,先在 WPF 里面放一个 Canvas 控件,这个控件将被作为 MAUI 的画布。如此也能解答一些伙伴的疑惑,那就是 MAUI 接入 WPF 的话,能作为控件的形式接入,而不作为类似 WindowsFormsHost 的方式接入。如本文下面的代码,只是提供一个 Canvas 控件,让 MAUI 将内容绘制在这个 Canvas 上。如此可见 MAUI 的大的方面的设计还是很好

<Canvas x:Name="Canvas" />

在后台代码里面,将创建 XamlCanvas 类型的 _canvas 字段,同时将上面代码的 Canvas 传入

public partial class MainWindow : Window{    public MainWindow(){InitializeComponent();_canvas.Canvas = Canvas;SizeChanged += (source, args) => Draw();}    public IDrawable Drawable{        get => _drawable;        set{_drawable = value;Draw();}}    private void Draw(){        if (_drawable != null){            using (_canvas.CreateSession()){_drawable.Draw(_canvas, new RectF(0, 0, (float) Canvas.Width, (float) Canvas.Height));}}}    private readonly XamlCanvas _canvas = new XamlCanvas();    private IDrawable _drawable;
}

以上代码的 XamlCanvas 继承了 ICanvas 接口。在 MAUI 的自绘里面,最重要的就是 ICanvas 接口,这是一个表示画布的接口,在这个接口里面实现了具体的绘制的抽象 API 定义。换句话说,如果你想要接入自己想要的其他平台,那很重要的一点就是去实现 ICanvas 的功能

以上的 XamlCanvas 是属于库提供的功能,将通过传入的 Canvas 实现对接 MAUI 和 WPF 的逻辑

有了画布之后,想要在界面绘制内容,那还需要告诉框架层想要画出什么内容。这就是属于业务层的内容了,在业务层里面,将需要继承 IDrawable 接口,实现 Draw 方法。在 Draw 方法进行业务层的渲染

例如一个画线的业务功能,可以使用如下实现方式

class DrawLines : IDrawable{        public void Draw(ICanvas canvas, RectF dirtyRect){canvas.DrawLine(50, 20.5f, 200, 20.5f);canvas.DrawLine(50, 30.5f, 200, 30.5f);}}

将 DrawLines 的对象设置给 Drawable 属性,即可看到界面画出线

以上的 DrawLines 就是属于 通用 MAUI 渲染层 的逻辑,将这段代码拿出来,可以跑在使用其他底层渲染技术但是接入 Microsoft.Maui.Graphics 的渲染技术,例如底层换成是 Win2D 等。如此即可通过造上层的 通用 MAUI 渲染层的逻辑,从而搭建起界面效果的生态。更多自定义的绘图,请看 MAUI 自定义绘图入门 - lindexi - 博客园

我十分推荐大家跑一下我的 demo 从而了解到当前的 MAUI 的实现进度

本文测试代码放在github 和 gitee 欢迎访问

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git initgit remote add origin https://gitee.com/lindexi/lindexi_gd.gitgit pull origin 8d4c37dbbde83e03a6daa4e3454a5d007c64dffe

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git

获取代码之后,进入 RijoqicainejoHifolurqall 文件夹

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/285639.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[转]redis 5.0.5 5分钟搭建redis集群

环境&#xff1a;centos 7 1&#xff1a;下载并安装redis ​​​​​​​$ wget http://download.redis.io/releases/redis-5.0.5.tar.gz$ tar xzf redis-5.0.5.tar.gz$ cd redis-5.0.5$ make redis 5.0版本 集群搭建不需要我们安装ruby就可以搭建成功&#xff0c;并且redis…

【土地评价与土地管理】案例:某地区柑橘种植适宜性评价

文章目录 一、确定评价单元二、评价因子选择三、评价因子权重的确定四、构建评价分级标准五、综合评价六、适宜性等级划分七、得出适宜性评价结果柑橘种植所需的自然条件: 柑橘果树生长发育、开花结果与温度、日照、水分(湿度)、土壤以及风、海拔、地形和坡向等环境条件紧密相…

django中怎样生成非HTML格式的内容。

某些时候可能有这种需求。在网页中点击一个链接或者一个button希望返回一张图片、一个pdf文档、一个csv文档等而非HTML。在diango中非常easy做到这些。django中的view用来接收http request并返回web response。通常情况下&#xff0c;返回的内容为HTML&#xff0c;但其可以返回…

Window.document对象

一、找到元素&#xff1a; docunment.getElementById("id")&#xff1b;根据id找&#xff0c;最多找一个&#xff1b; var a docunment.getElementById("id");将找到的元素放在变量中&#xff1b; docunment.getElementsByName("name")&am…

C# 读写文件从用户态切到内核态,到底是个什么流程?

一&#xff1a;背景 1. 一个很好奇的问题我们在学习 C# 的过程中&#xff0c;总会听到一个词叫做 内核态 &#xff0c;比如说用 C# 读写文件&#xff0c;会涉及到代码从 用户态 到 内核态 的切换&#xff0c;用 HttpClient 获取远端的数据&#xff0c;也会涉及到 用户态 到 内核…

C语言九十四之请编写函数fun(char *str, int n),其功能是:使字符串str的前导*号不能多余n个,若多于n个,则删除多余的*号,若少于或等于n个,则不做处理。

📃个人主页:个人主页 🔥系列专栏:C语言试题200例目录 💬推荐一款刷算法、笔试、面经、拿大公司offer神器 👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 规定输入的…

【土地评价与土地管理】案例:某地区土地农业利用潜力评价

文章目录 一、确定评价单元二、拟定潜力评价系统表、确定指标权重三、指标评价四、评定潜力等级五、得出潜力评价结果一、确定评价单元 土地潜力评价单元采用地块作为评价单元,此地块是建立在土地利用现状的基础上, 综合土地的自然属性来确定,评价单元界线与土地现有界线基本…

WIKIOI 1519 过路费

1519 过路费 1519 过路费 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 大师 Master 题解 题目描述 Description 在某个遥远的国家里&#xff0c;有 n个城市。编号为 1,2,3,…,n。这个国家的政府修建了m 条双向道路&#xff0c;每条道路连接着两个城市。政府规定从城市…

code point,code unit

2019独角兽企业重金招聘Python工程师标准>>> 从一段API描述谈起&#xff1a; 在String的length的API中描述是这样的&#xff01; lengthpublic int length() Returns the length of this string. The length is equal to the number of 16-bit Unicode characters i…

Android之解决JsonObject里面的JsonArray数据会有斜杠问题

1、问题 本地保存了多个json格式的字符串 {"event":"sdk_ad_request_status","timestamp":1640180549231,"ad_app_id":"10104","pool_test":0,"ad_type":0,"ad_request_time":0,"requ…

【土地评价与土地管理】案例:兰州市榆中县农用地分等

文章目录 一、资料收集二、确定标准耕作制度、基准作物、指定作物、光温(气候生产潜力)三、划分指标区,确定分等因素及权重四、编制“指定作物-分等因素-自然质量分”记分规则表五、绘制分等因素分值图,划分分等单元六、计算农用地自然质量分七、计算自然质量等指数八、计算…

.NET7之MiniAPI(特别篇) :Preview5优化了JWT验证(下)

Preview5对策略验证的方式没有改变&#xff0c;只不过内置了Token的生成&#xff0c;和《.NET6之MiniAPI(十)&#xff1a;基于策略的身份验证和授权》的验证方式基本相同&#xff0c;都是生成和验证使用的验证参数要一致&#xff0c;用继承AuthorizationHandler的子类来作每次请…

业务多变的公司上云后蒸蒸日上

一、云服务器与传统服务器的对比 1&#xff09;、传统服务器 传统服务器是一个独立的硬件设备,可以理解成是一台放在机房的高配置电脑,可根据需求安装各种操作系统以及配置各种环境,性能也比较强大。 2&#xff09;、云服务器 云服务器是构建在硬件服务器集群之上&#xff0c;…

2016福州大学软件工程第四次团队作业-系统设计成绩汇总

第四次团队作业——系统设计打分统计结果如下&#xff1a; 学号组别团队分数贡献比例个人分数031401433606notconnected141613.83031402606606notconnected141413.33031402618606notconnected141814.34031402629606notconnected141413.33031402631606notconnected141914.590314…

[转]在C#中像Python一样编写TensorFlow机器学习代码

机器学习是一个令人激动人心的领域&#xff0c;一直有新的技术突破。研究人员不断推动机器智能的提升&#xff0c;教机器如何听说读写——这些曾经是我们人类专属的技能。机器学习的首选语言是Python&#xff0c;最受欢迎的库是Google的TensorFlow。几乎所有的代码示例都是用Py…

【土地评价与土地管理】教案 第一章:土地评价要素的选择

文章目录 1.1 土地构成要素与其农业利用1、光能条件2、热量条件3、降水条件1.1 土地构成要素与其农业利用 1、光能条件  光能是绿色植物进行光合作用和生物运动发展的主要能源  太阳辐射、日照时数  太阳辐射量随地域和季节变化较大,导致了土地利用的多样性和土地资源…

Blazor University (33)表单 —— EditContext、FieldIdentifiers

原文链接&#xff1a;https://blazor-university.com/forms/editcontext-fieldidentifiers-and-fieldstate/EditContext、FieldIdentifiers 和 FieldState请注意&#xff0c;对于那些希望了解 Blazor 如何“在后台”工作的人来说&#xff0c;这是一个高级主题。无需了解此信息即…

Flutter之Container的宽度如何设置为手机屏幕宽度

1、问题 Container的宽度如何设置为手机屏幕宽度 2、解决办法 width: MediaQuery.of(context).size.width,Row(children: [Container(height: 40,width: MediaQuery.of(context).size.width,// width: double.infinity,color: Colors.red,child: Row(children: [Containe…

团队项目开发篇章8

例会时间&#xff1a;2016.11.3 整理&#xff1a;姬索肇 例会照片 每个人的工作 任务分配 我们今天与王鹿鸣学长和李云涛学长针对团队开发过程中遇到的问题进行了讨论&#xff0c;非常感谢学长们的热心帮助&#xff0c;同时我们也被他们强大的编程能力所折服~ 在这里为学长们点…

MongoDB常用命令

启动MongoDB$mongod --fork --logpath/data/log/r3.log--fork 允许mongod后台运行&#xff0c;但是必须指定日志记录文件路径&#xff08;Enables a daemon mode that runs the mongos process in the background.&#xff09;--logpath 指定日志记录文件路径 导出Collections$…