MAUI与Blazor共享一套UI,媲美Flutter,实现Windows、macOS、Android、iOS、Web通用UI

1. 前言

距离上次发《MAUI初体验:爽》一文已经过去2个月了,本计划是下半年或者明年再研究MAUI的,现在计划提前啦,因为我觉得MAUI Blazor挺有意思的:在Android、iOS、macOS、Windows之间共享UI,一处UI增加或者修改,就能得到一致的UI体验。

看看这篇文章《Blazor Hybrid/MAUI 简介和实战[1]》对MAUI Blazor的说明:

MAUI

.NET 多平台应用程序 UI (.NET MAUI) 是一个跨平台框架,用于使用 C# 和 XAML 创建本机移动和桌面应用程序, 使用 .net MAUI,可以开发可在 Android、iOS、macOS 上运行的应用,Windows 以及从单个共享代码库运行的应用。

Blazor Hybrid 应用和 .NET MAUI

Blazor Hybrid 支持内置于 .NET 多平台应用 UI (.NET MAUI) 框架。.NET MAUI 包含 BlazorWebView 控件,该控件运行将 Razor 组件呈现到嵌入式 Web View 中。通过结合使用 .NET MAUI 和 Blazor,可以跨移动设备、桌面设备和 Web 重复使用一组 Web UI 组件。

今天就分享如何在Blazor Server、Blazor Wasm、MAUI Blazor之间共享UI的实验,这一步完成,后面开发应用时就方便多了(只针对UI修改)。

2. 先来体验下各端最终效果

  • Blazor Server:http://server.dotnet9.com/

  • Blazor Wasm:http://wasm.dotnet9.com/

  • MAUI(Android\Windows\macOS):https://github.com/dotnet9/Dotnet9/tree/develop/src/Dotnet9.MAUI(源码自行编译)

Windows桌面、Blazor Server(在线)、Blazor Wasm(在线)、Android效果

cbaebfbb91876a681f08f22372ac0c57.gif

iOS、macOS桌面效果

12303d8f326c18bbb313ed8cecece356.png

MAUI各端未做发布文件体验(需要做相应平台的发布签名等操作),大家可以按下面介绍的方法创建项目编译体验一下。

iOS和macOS效果感谢青城同学[2]提供的图片素材,站长mbp安装了最新的macOS,xCode也是最新的,可能因为预览版macOS原因,xCode无法打开,间接影响了maui编译?

f37d0482fec644c0d57d74c3cc118760.png

3. 新建项目

关于MAUI的环境搭建可参考这篇文章《在MAUI中使用Masa Blazor》,本文不再介绍环境搭建,直接使用VS 2022最新预览版项目模板创建项目。

3.1 创建Blazor Server项目:Dotnet9.Server

a85a5b682b1f07445da2ff7dba4cb6d8.png

3.2 创建Blazor WebAssembly项目:Dotnet9.Wasm

a91d961c5835607a6ed9f8a1731d202b.png

3.3 创建MAUI Blazor项目:Dotnet9.MAUI

0fd4985f12ecea54296e1ede0954b35b.png

3.4 查找共同点

在3个项目的上一层目录,打开PowerShell,输入tree /f查看详细的目录文件组织结构:

d9586ef55a357ae78c121286bf0414bc.gif

仔细查看三个模板项目文件结构,我们找出共同的文件查看:

文件夹 PATH 列表
卷序列号为 76F5-AF62
C:.
│  Dotnet9.sln
│
├─Dotnet9.MAUI
【1 这里省略数个文件】
│  │
│  ├─Data
│  │      WeatherForecast.cs
│  │      WeatherForecastService.cs
│  │
│  ├─Pages
│  │      Counter.razor
│  │      FetchData.razor
│  │      Index.razor
【2 这里省略数个文件】
│  │
│  ├─Shared
│  │      MainLayout.razor
│  │      MainLayout.razor.css
│  │      NavMenu.razor
│  │      NavMenu.razor.css
│  │      SurveyPrompt.razor
【3 这里省略数个文件】
│
├─Dotnet9.Server
│  │  App.razor
【4 这里省略数个文件】
│  │
│  ├─Data
│  │      WeatherForecast.cs
│  │      WeatherForecastService.cs
│  │
│  ├─Pages
│  │      Counter.razor
│  │      Error.cshtml
│  │      Error.cshtml.cs
│  │      FetchData.razor
│  │      Index.razor
│  │      _Host.cshtml
│  │      _Layout.cshtml
│  │
│  ├─Properties
│  │      launchSettings.json
│  │
│  ├─Shared
│  │      MainLayout.razor
│  │      MainLayout.razor.css
│  │      NavMenu.razor
│  │      NavMenu.razor.css
│  │      SurveyPrompt.razor
【5 这里省略数个文件】
│
└─Dotnet9.Wasm
【6 这里省略数个文件】│├─Pages│      Counter.razor│      FetchData.razor│      Index.razor│├─Properties│      launchSettings.json│├─Shared│      MainLayout.razor│      MainLayout.razor.css│      NavMenu.razor│      NavMenu.razor.css│      SurveyPrompt.razor
【7 这里省略数个文件】

发现都有Data目录和Pages目录(其中Wasm项目没有Data目录,使用的示例类是直接写在FetchData.razor文件@code{}中的),那把这部分文件直接提取到类库中就可以了,那就做吧。

4. 提取UI到Razor类库

创建Razor类库:Dotnet9.WebApp

5771f4f1ce243638a12c8503bcb6a728.png

下面开始UI的提取

5839a63dd4e748807d00b4b0b03fd145.png

如上图,将Dotnet9.MAUI项目的DataPagesShared三个目录外加Main.razor文件剪切到Dotnet9.WebApp项目中,然后修改剪切后相应文件的命名空间Dotnet9.MAUI[xxx]Dotnet9.WebApp[xxx],打开Dotnet9.WebApp项目的_Import.razor文件,参考Dotnet9.MAUI项目的_Import.razor文件部分命名空间,修改如下:

@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using Dotnet9.WebApp
@using Dotnet9.WebApp.Shared

上面部分命名空间可以删除(未尝试),编译Dotnet9.WebApp项目,检查是否正确编译。

5. 各端项目修改

5.1 MAUI项目

  1. 添加Dotnet9.WebApp项目引用

  2. Program.csusing Dotnet9.MAUI.Data;改为using Dotnet9.WebApp.Data

  3. 删除DataPagesShared三个目录外加Main.razor文件,上一步是剪切的话这步省略

  4. 修改_Imports.razor文件,主要是添加Dotnet9.WebApp项目命名空间引用

@using System.Net.Http
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using Dotnet9.MAUI
@using Dotnet9.WebApp
@using Dotnet9.WebApp.Shared
  1. MauiProgram.cs修改引用的命名空间:using Dotnet9.MAUI.Data; => using Dotnet9.WebApp.Data;

  2. 打开MainPage.xaml,对路由组件命名空间的引用修改

添加命名空间xmlns:webApp="clr-namespace:Dotnet9.WebApp;assembly=Dotnet9.WebApp",修改代码如下:

修改前:

<RootComponent Selector="#app" ComponentType="{x:Type local:Main}" />

修改后:

<RootComponent Selector="#app" ComponentType="{x:Type webApp:Main}" />

修改完毕,编译运行Dotnet9.MAUI项目吧,接下来修改Dotnet9.Server项目。

5.2 Blazor Server项目

  1. 添加Dotnet9.WebApp项目引用

  2. Program.csusing Dotnet9.Server.Data;改为using Dotnet9.WebApp.Data;

  3. 删除Data目录

  4. 删除Pages目录中的Counter.razorFetchData.razorIndex.razor三个文件(包括同名的.cs.css文件)

  5. 删除Shared目录

  6. 修改_Imports.razor文件,主要是添加Dotnet9.WebApp项目命名空间引用

@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using Dotnet9.Server
@using Dotnet9.WebApp
@using Dotnet9.WebApp.Shared
  1. 打开./Pages/_Host.cshtml文件,添加命名空间引用@using Dotnet9.WebApp,修改代码如下:

修改前:

<component type="typeof(App)" render-mode="ServerPrerendered" />

修改后:

<component type="typeof(Main)" render-mode="ServerPrerendered" />

修改完毕,编译运行Dotnet9.Server项目吧,接下来修改Dotnet9.Wasm项目。

5.3 Blazor Wasm项目

  1. 添加Dotnet9.WebApp项目引用

  2. 删除PagesShared目录外加App.razor文件

  3. Program.csusing Dotnet9.Wasm;改为using Dotnet9.WebApp;,同时修改代码

修改前

builder.RootComponents.Add<App>("#app");

修改后

builder.RootComponents.Add<Main>("#app");
  1. 修改_Imports.razor文件,主要是添加Dotnet9.WebApp项目命名空间引用

@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using Dotnet9.Server
@using Dotnet9.WebApp
@using Dotnet9.WebApp.Shared

修改完毕,编译运行Dotnet9.Wasm项目,至此三种项目模板已经修改完成,最终解决方案如下图:

f229cb995649e05c6bc3e12f1f367f94.png

6 总结

总结就是下图:

7cfb94053f52bb951d61a5d67b5554f7.png
  • Dotnet9.WebApp:blazor组件相关的代码、路由组件等放在这个工程,供其他项目引用

  • Dotnet9.Server:Blazor Server模板项目

  • Dotnet9.Wasm:Blazor WebAssembly项目

  • Dotnet9.MAUI:MAUI Blazor项目

一句话:将UI封装到Razor类库Dotnet9.WebApp,其他终端工程(Dotnet9.ServerDotnet9.MAUIDotnet9.Wasm)引用此工程即可实现UI共享。

  • 本文代码地址:https://github.com/dotnet9/Dotnet9[3]

  • 原文:https://dotnet9.com/2022/06/Share-razor-library-between-maui-and-blazor-server-or-client[4]

参考

  1. ASP.NET Community Standup - Native client apps with Blazor Hybrid[5]

  2. Blazor一份代码在Blazor WebAssembly和Blazor Server之间任意切换[6]

  3. 微软MAUI文档[7]

  4. 微软Blazor文档[8]

  5. 学Blazor[9]

参考资料

[1]

Blazor Hybrid/MAUI 简介和实战: https://www.cnblogs.com/densen2014/p/16240966.html

[2]

青城同学: https://iwscl.com/

[3]

https://github.com/dotnet9/Dotnet9: https://github.com/dotnet9/Dotnet9

[4]

https://dotnet9.com/2022/06/Share-razor-library-between-maui-and-blazor-server-or-client: https://dotnet9.com/2022/06/Share-razor-library-between-maui-and-blazor-server-or-client

[5]

ASP.NET Community Standup - Native client apps with Blazor Hybrid: https://www.youtube.com/watch?v=7UM6s0QPvRQ

[6]

Blazor一份代码在Blazor WebAssembly和Blazor Server之间任意切换: https://www.bilibili.com/video/BV1ty4y137yA?spm_id_from=333.337.search-card.all.click&vd_source=fc9bd0ca1f113a165ad3ebf4fb79b124

[7]

微软MAUI文档: https://docs.microsoft.com/zh-cn/dotnet/maui/?WT.mc_id=dotnet-35129-website

[8]

微软Blazor文档: https://docs.microsoft.com/zh-cn/aspnet/core/blazor/?WT.mc_id=dotnet-35129-website&view=aspnetcore-6.0

[9]

学Blazor: https://dotnet9.com/album/Let-us-learn-blazor-together

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

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

相关文章

dns 报文格式

最近学习了下DNS的格式&#xff0c;发现很多内容都是转载自同一个而且说的不是很清楚&#xff0c;特再整理下具体可以查看RFC1035 http://www.ietf.org/rfc/rfc1035.txt有详细的解释对于英语理解不是很好和懒得看这么长的可以看下本文首先是DNS数据帧的格式-------------------…

input file实现批量上传

1、需求实现word批量上传。 2、使用插件jquery-form.js 3、html代码 注意 multiple"multiple" 1 <form id"frm_upload" method"post" enctype"multipart/form-data"> 2   <input type"file" id"filepath&qu…

【Pix4d精品教程】Pix4d修编正射影像DOM的两种方法案例详解

《无人机航空摄影测量精品教程》合集目录(Pix4d、CC、EPS、PhotoScan、Inpho) DOM修编前: DOM修编后: 文章摘要: Pix4d内业数据处理通常会生成点云、DSM和DOM等产品,DSM经过精编可以生成精准的DEM,而DOM一般情况下,存在比如房屋边缘被拉花,或者存在噪点的情况

删除Linux下/tmp目录引起的不正常登录系统

现象&#xff1a;/tmp占用400M的空间(里面全部是乱七八糟的东西) 动作&#xff1a;删除/tmp目录 后果&#xff1a;造成只能启动到控制台模式 应急&#xff1a; 1 创建目录&#xff1a;#mkdir /tmp 结果系统在控制台模式登录和X windows模式登录状态间反复切换&#xff0c;不能进…

C语言试题八十五之狼追兔子问题

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

[转]快速使用FileProvider解决Android7.0文件权限问题

升级到Android7.0之后&#xff0c;启动系统相机或者截图&#xff0c;传入URI的时候可能会导致程序闪退崩溃。这是因为7.0的新的文件权限导致的。下面是解决这个问题的快速解决方案。 问题代码 在7.0可能会出问题的代码&#xff1a; final String CACHE_IMG Environment.getExt…

终于找到了,开源的Vue3+.NET6通用管理后台!

据说80%的.NET项目都是管理后台&#xff0c;然而能用上Vue3.NET6的管理后台并不多见。这里分享一套Vue3 Axios TS Vite ElementUI Plus .NET 6 WebAPI JWT SqlSugar的前后端分离架构的通用管理后台源码数据库脚本&#xff0c;还有与之配套录制的一组视频教程&#xff0c;全部打…

【Pix4d精品教程】Pix4d模型成果导出OSGB并加载OSGB到EPS进行三维测图完美案例教程

《无人机航空摄影测量精品教程》合集目录(Pix4d、CC、EPS、PhotoScan、Inpho) 在垂直摄影中,Pix4d也可以生成漂亮的三维模型,并导出为OSGB,加载到EPS进行三维测图。首先来看生成的三维格网纹理和EPS三维模型加载效果。 Pix4d生成的三维格网纹理: EPS加载OSGB模型效果: 文…

Vim 批量替换

假设在非Win系统下。 想批量替换文本不再是Ctrl&#xff0b;F那么简单了&#xff0c; 一般用Vim来做批量替换&#xff0c; 略微复杂点&#xff1a; 比如将192.168.0.1替换为192.168.0.2 :%s/192.168.0.1/192.168.0.2/g

Android实现ListView(1)

昨天有个朋友问我Android ListView列表视图&#xff0c;遇到了点错误&#xff0c;今天我给大家演示&#xff0c;具体实现见图&#xff1a; 1&#xff1a;创建一个item布局layout/item.xml 2&#xff1a;创建一个ListViewActivity类&#xff0c;但是必须继承ListActivity&#x…

WolframAlpha 的使用

WolframAlpha 1. 求解复杂方程组 ab−4abc2ac1直接点开网站&#xff0c;在输入框中输入&#xff0c;ab-4;abc2;ac1;&#xff08;逗号分割开来&#xff09;&#xff0c; 转载于:https://www.cnblogs.com/mtcnn/p/9423087.html

C语言试题八十六之兔子生兔子问题

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

聊聊 C# 中的 Composite 模式

‍写在前面 Composite组合模式属于设计模式中比较热门的一个&#xff0c;相信大家对它一定不像对访问者模式那么陌生&#xff0c;毕竟谁又没有遇到过树形结构呢。不过所谓温故而知新&#xff0c;我们还是从一个例子出发&#xff0c;起底一下这个模式吧。一个简单例子 设想我们…

140种Python标准库、第三方库和外部工具都有了

导读&#xff1a;Python数据工具箱涵盖从数据源到数据可视化的完整流程中涉及到的常用库、函数和外部工具。其中既有Python内置函数和标准库&#xff0c;又有第三方库和工具。 这些库可用于文件读写、网络抓取和解析、数据连接、数清洗转换、数据计算和统计分析、图像和视频处理…

【CC精品教程】任务一:CC新建工程、添加照片、相机参数设置、选择坐标系统

《无人机航空摄影测量精品教程》合集目录(Pix4d、CC、EPS、PhotoScan、Inpho) 同Pix4d一样,CC(Context Capture),也称Smart 3D,也是无人机航测中人手必备的一款软件,在空三运算,三维模型构建等倾斜摄影测量方面有很大的优势,精度也相当高。本CC系列精品教程从项目的角…

C语言试题八十七之实现选择排序算法

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

java concurrent之前戏synchronized

对于多线程共享资源的情况须要进行同步&#xff0c;以避免一个线程的修改被还有一个线程的修改所覆盖。最普遍的同步方式就是synchronized。把代码声明为synchronized。有两个重要后果&#xff0c;一般是指该代码具有 原子性&#xff08;atomicity&#xff09;和 可见性&#x…

开源项目【zheng】搭建流程

2019独角兽企业重金招聘Python工程师标准>>> 搭建过程 项目地址 https://gitee.com/shuzheng/zheng这两篇写的比较详细的搭建过程&#xff0c;结合一下就没什么问题了。 https://my.oschina.net/yzuzhang/blog/1538555http://www.jianshu.com/p/b2fb42e17b581.JDK 1…

简述HTML DOM及其节点分类

在JavaScript中&#xff0c;document这个对象大家一定很熟悉&#xff0c;哪怕是刚刚开始学习的新人&#xff0c;也会很快接触到这个对象。而document对象不仅仅是一个普通的JavaScript内置对象&#xff0c;它还是一个巨大API的核心对象&#xff0c;这个巨大的API就是DOM&#x…

【CC精品教程】任务二:导入像控点、差分POS,空三平差权重设置,提交自由空三

《无人机航空摄影测量精品教程》合集目录(Pix4d、CC、EPS、PhotoScan、Inpho) 【CC精品教程】任务一:CC新建工程、添加照片、相机参数设置、选择坐标系统 本任务接着上一个任务,继续完成CC项目作业,主要内容有:导入像控点、选择空间参考系统,导入差分POS,空三平差权重设…