1. 前言

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

看看这篇文章《Blazor Hybrid/MAUI 简介和实战》对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. 先来体验下各端最终效果

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

iPad Air、iOS、macOS桌面效果

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

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

macOS版本和xCode版本

xCode为不可用状态

VS编译出错,后面再解决

用mbp的同学建议不要安装预览版操作系统,不要当勇士....

3. 新建项目

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

3.1 创建Blazor Server项目:Dotnet9.Server

3.2 创建Blazor WebAssembly项目:Dotnet9.Wasm

3.3 创建MAUI Blazor项目:Dotnet9.MAUI

3.4 查找共同点

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

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

  1. 文件夹 PATH 列表
  2. 卷序列号为 76F5-AF62
  3. C:.
  4. Dotnet9.sln

  5. ├─Dotnet9.MAUI
  6. 1 这里省略数个文件】

  7. ├─Data
  8. WeatherForecast.cs
  9. WeatherForecastService.cs

  10. ├─Pages
  11. Counter.razor
  12. FetchData.razor
  13. Index.razor
  14. 2 这里省略数个文件】

  15. ├─Shared
  16. MainLayout.razor
  17. MainLayout.razor.css
  18. NavMenu.razor
  19. NavMenu.razor.css
  20. SurveyPrompt.razor
  21. 3 这里省略数个文件】

  22. ├─Dotnet9.Server
  23. App.razor
  24. 4 这里省略数个文件】

  25. ├─Data
  26. WeatherForecast.cs
  27. WeatherForecastService.cs

  28. ├─Pages
  29. Counter.razor
  30. Error.cshtml
  31. Error.cshtml.cs
  32. FetchData.razor
  33. Index.razor
  34. _Host.cshtml
  35. _Layout.cshtml

  36. ├─Properties
  37. launchSettings.json

  38. ├─Shared
  39. MainLayout.razor
  40. MainLayout.razor.css
  41. NavMenu.razor
  42. NavMenu.razor.css
  43. SurveyPrompt.razor
  44. 5 这里省略数个文件】

  45. └─Dotnet9.Wasm
  46. 6 这里省略数个文件】

  47. ├─Pages
  48. Counter.razor
  49. FetchData.razor
  50. Index.razor

  51. ├─Properties
  52. launchSettings.json

  53. ├─Shared
  54. MainLayout.razor
  55. MainLayout.razor.css
  56. NavMenu.razor
  57. NavMenu.razor.css
  58. SurveyPrompt.razor
  59. 7 这里省略数个文件】

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

4. 提取UI到Razor类库

创建Razor类库:Dotnet9.WebApp

下面开始UI的提取

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

  1. @using System.Net.Http
  2. @using Microsoft.AspNetCore.Authorization
  3. @using Microsoft.AspNetCore.Components.Forms
  4. @using Microsoft.AspNetCore.Components.Routing
  5. @using Microsoft.AspNetCore.Components.Web
  6. @using Microsoft.AspNetCore.Components.Web.Virtualization
  7. @using Microsoft.JSInterop
  8. @using Dotnet9.WebApp
  9. @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项目命名空间引用
  1. @using System.Net.Http
  2. @using Microsoft.AspNetCore.Components.Forms
  3. @using Microsoft.AspNetCore.Components.Routing
  4. @using Microsoft.AspNetCore.Components.Web
  5. @using Microsoft.AspNetCore.Components.Web.Virtualization
  6. @using Microsoft.JSInterop
  7. @using Dotnet9.MAUI
  8. @using Dotnet9.WebApp
  9. @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",修改代码如下:

修改前:

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

修改后:

  1. <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项目命名空间引用
  1. @using System.Net.Http
  2. @using Microsoft.AspNetCore.Authorization
  3. @using Microsoft.AspNetCore.Components.Authorization
  4. @using Microsoft.AspNetCore.Components.Forms
  5. @using Microsoft.AspNetCore.Components.Routing
  6. @using Microsoft.AspNetCore.Components.Web
  7. @using Microsoft.AspNetCore.Components.Web.Virtualization
  8. @using Microsoft.JSInterop
  9. @using Dotnet9.Server
  10. @using Dotnet9.WebApp
  11. @using Dotnet9.WebApp.Shared
  1. 打开./Pages/_Host.cshtml文件,添加命名空间引用@using Dotnet9.WebApp,修改代码如下:

修改前:

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

修改后:

  1. <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;,同时修改代码

修改前

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

修改后

  1. builder.RootComponents.Add<Main>("#app");
  1. 修改_Imports.razor文件,主要是添加Dotnet9.WebApp项目命名空间引用
  1. @using System.Net.Http
  2. @using Microsoft.AspNetCore.Authorization
  3. @using Microsoft.AspNetCore.Components.Authorization
  4. @using Microsoft.AspNetCore.Components.Forms
  5. @using Microsoft.AspNetCore.Components.Routing
  6. @using Microsoft.AspNetCore.Components.Web
  7. @using Microsoft.AspNetCore.Components.Web.Virtualization
  8. @using Microsoft.JSInterop
  9. @using Dotnet9.Server
  10. @using Dotnet9.WebApp
  11. @using Dotnet9.WebApp.Shared

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

6 总结

总结就是下图:

  • Dotnet9.WebApp:blazor组件相关的代码、路由组件等放在这个工程,供其他项目引用
  • Dotnet9.Server:Blazor Server模板项目
  • Dotnet9.Wasm:Blazor WebAssembly项目
  • Dotnet9.MAUI:MAUI Blazor项目

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

参考

  1. ASP.NET Community Standup - Native client apps with Blazor Hybrid
  2. Blazor一份代码在Blazor WebAssembly和Blazor Server之间任意切换
  3. 微软MAUI文档
  4. 微软Blazor文档
  5. 学Blazor

MAUI与Blazor共享一套UI,媲美Flutter,实现Windows、macOS、Android、iOS、Web通用UI的更多相关文章

  1. 工作流,WEB框架,UI组件网络收集整理

    工作流,WEB框架,UI组件网络收集整理 在博客园上逛了好多年,随手收录了一些工作流,WEB开发框架,UI组件,现在整理一下与大家分享. 由于个人能力与精力有限,望各位园友在评论中补充,我将全部整理到 ...

  2. Flutter 1.0 正式版: Google 的跨平台 UI 工具包

    今天我们非常高兴的宣布,Flutter 的 1.0 版本正式发布!Flutter 是 Google 为您打造的 UI 工具包,帮助您通过一套代码同时在 iOS 和 Android 上构建媲美原生体验的 ...

  3. 2015年最全的移动WEB前端UI框架

    目前,众多互联网公司APP都嵌入了大量的HTML5,移动端的开发越来越重视,HTML5的运用场景也越来越多了.在移动WEB开发的过程中,使用合适的移动WEB UI框架可以大大提升我们的开发效率.下面P ...

  4. web前端UI框架

    分类:WEB前端 时间:2016年1月13日 目前,众多互联网公司APP都嵌入了大量的HTML5,移动端的开发越来越重视,HTML5的运用场景也越来越多了.在移动WEB开发的过程中,使用合适的移动WE ...

  5. Flutter 1.0 正式版: Google 的便携 UI 工具包

    简评:所以 React-Native 和 Flutter 该怎么选? 在 10 个月前的 MWC 上,谷歌发布了 Flutter 的 Beta 版本,给跨平台应用开发带来了一种全新的选择,昨天谷歌正式 ...

  6. Huxley 是一个用于Web应用 UI 测试的工具

    Huxley 是一个用于Web应用 UI 测试的工具,由  Pete Hunt 和 Maykel Loomans 用 Python 开发. UI 测试比较令人头疼. UI测试不好写,而且很容易失效: ...

  7. 免费素材下载:iOS 8 矢量 UI 素材套件

    小伙伴们,苹果终于在今天凌晨推送了 iOS 8 的正式版.虽然该系统并未与 iPhone6 发布会同时亮相,但对于已经提前体验尝鲜过测试版的同学来说并不陌生.iOS 8 几乎每个图标都进行了重新设计, ...

  8. 重新想象 Windows 8 Store Apps (56) - 系统 UI: Scale, Snap, Orientation, High Contrast 等

    [源码下载] 重新想象 Windows 8 Store Apps (56) - 系统 UI: Scale, Snap, Orientation, High Contrast 等 作者:webabcd ...

  9. Android子线程更新UI主线程方法之Handler

    背景: 我们开发应用程序的时候,处于线程安全的原因子线程通常是不能直接更新主线程(UI线程)中的UI元素的,那么在Android开发中有几种方法解决这个问题,其中方法之一就是利用Handler处理的. ...

随机推荐

  1. Python Django项目日志查询系统

    该项目适合中小型公司日志查询工作.大型公司可以使用elk等.该系统其实就是调用了absible命令去查日志,然后把输出的信息输到页面查看. 日志查询系统 维护手册 作者:陈土锋 日期:2020年6月1 ...

  2. librttopo 安装

    librttopo 安装 官网 下载地址 https://git.osgeo.org/gitea/rttopo/librttopo/tags 什么是 librttopo? The RT Topolog ...

  3. String类为什么被设计成不可变类

    1.享元模式: 1.共享元素模式,也就是说:一个系统中如果有多处用到了相同的一个元素,那么我们应该只存储一份此元素,而让所有地方都引用这一个元素. 2.Java中String就是根据享元模式设计的,而 ...

  4. vwware workstation虚机网络配置NAT

    1.在编辑中选择虚拟网络编辑器,新增NAT模式网络适配器,如下图: 2.在虚拟机中选择设置,在网络适配器中自定义为上一步配置的网络适配器,如下图: 3.进入虚拟机后,编辑/etc/sysconfig/ ...

  5. Lumia一键刷稳定版 Win10 arm 及其报错处理

    前言 之前我发了一篇Lumia1520 刷Win10 arm双系统的文章,不过后来发现那个方法对小白来说太不友好,且系统也不稳定,所以我找到了更好的方法 刷机 我们可以利用刷机迷进行刷机,支持一键刷机 ...

  6. 计算机编码规则之:Base64编码

    目录 简介 Base64和它的编码原理 Base64的变体 Base64的编码细节 总结 简介 我们知道计算机中的文件可以分为两种,一种是人肉眼可读的文本类文件,一种是肉眼不可读的二进制文件.一般来说 ...

  7. ElasticSearch7.3学习(十九)---- deep paging

    1.什么是deep paging 根据相关度评分倒排序,所以分页过深,协调节点会将大量数据聚合分析. 2.deep paging 性能问题 1消耗网络带宽,因为所搜过深的话,各 shard 要把数据传 ...

  8. JavaWeb和WebGIS学习笔记(六)——使用ArcGIS for Server发布地图服务

    系列链接: Java web与web gis学习笔记(一)--Tomcat环境搭建 Java web与web gis学习笔记(二)--百度地图API调用 JavaWeb和WebGIS学习笔记(三)-- ...

  9. .NET宝藏API之:IHostedService,后台任务执行

    我们在项目开发的过程中可能会遇到类似后台定时任务的需求,比如消息队列的消费者. 按照.NetF时的开发习惯首先想到的肯定是Windows Service,拜托,都什么年代了还用Windows服务(小声 ...

  10. Redis实现并发阻塞锁方案

    由于用户同时访问线上的下订单接口,导致在扣减库存时出现了异常,这是一个很典型的并发问题,本篇文章为解决并发问题而生,采用的技术为Redis锁机制+多线程的阻塞唤醒方法. 在实现Redis锁机制之前,我 ...