Maui的学习之路 --- Winui3深入探讨

学习Maui已经有一段时间,随着不断地深入,对Maui有了一些初步的了解。

我们都知道Maui为了保持平台原生特性,所以在每一个平台都使用了平台自身的原生开发框架,如在Windows系统使用了Winui3作为UI框架,Mac平台使用了UIKit作为UI框架,(我愿称之为“套娃”或者是对不同平台做了一层“抽象”),所以如果直接操作Maui的对象的某个属性或者方法实际他背后去转调了平台相关的属性或者方法。

有了这样的认识那么我们就会深刻的理解到如果我想改变某些东西,其实也可以自己去直接操作平台相关的方法,而并不一定需要操作Maui对象(如果Maui未提供这样的能力,你只能这么做)。

在做Windows桌面程序开发时,我们常常有这样的需求,你的exe程序同一时间只能运行一份(单例),你很希望程序打开就全屏,别人不能轻易关闭(通常在工业领域这样的需求极大)。

基于以上需求,我们来深入了解学习一下,如何实现:

首先使用Maui模板创建的每一个工程有有一个Platforms的目录,这个本质上是对应多平台的一个工程集合(在Xamarin中如果你需要构建一个真正的跨平台程序,实际是做不到的,你需要通过Xamarin.Form的模板创建不同平台的入口,然后抽出公用的平台无关逻辑来作为跨平台的共享资源),有了这个设计Maui真正实现了一份代码到处编译到处运行,而你在别的平台编译并不需要对工程做任何特别的改动(目前支持MacWindows平台编译)(这里不做深入探讨,如果你想了解MauiXamarin工程上的区别请看这个视频:.NET MAUI 跨平台开发合集_哔哩哔哩_bilibili[1]

其次对于Maui的可执行工程(非dll)来说,对应平台的程序的真正入口并非是MauiProgramMauiApplication,他实际是Platforms下对应的平台的Main或者是App,比如对Window来说,Maui启动程序的真正入口是Platforms/Windows/App这个对象。

Window单例实现

有了上面的认识作为基础,那么实现一个单例非常简单,在Wpf或者Winform上做过相同的设计,如今只需要搬运过来即可(在Wpf或是Winform实现单例的方式很多,最常用的是使用Mutex)实现方式请查阅:零食栏 - .NET MAUI Community Toolkit - .NET Community Toolkit | Microsoft Docs [2]在Platform/Windows/App.xaml.cs中增加单例检查

public partial class App : MauiWinUIApplication
{/// <summary>/// Initializes the singleton application object.  This is the first line of authored code/// executed, and as such is the logical equivalent of main() or WinMain()./// </summary>public App(){this.InitializeComponent();}static Mutex? __SingleMutex;protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();protected override void OnLaunched(LaunchActivatedEventArgs args){if (!IsSingleInstance()){//Process.GetCurrentProcess().Kill();Environment.Exit(0);return;}base.OnLaunched(args);}static bool IsSingleInstance(){const string applicationId = "813342EB-7796-4B13-98F1-14C99E778C6E";__SingleMutex = new Mutex(false, applicationId);GC.KeepAlive(__SingleMutex);try{return __SingleMutex.WaitOne(0, false);}catch (Exception){__SingleMutex.ReleaseMutex();return __SingleMutex.WaitOne(0, false);}}
}
实现一个无边框窗体

在这之前我其实已经写过一篇Maui在windows上实现无边框的方式,有兴趣的同学可以去查阅一下(链接:Window窗体设置)。Maui实际提供了一名为Window的类型,不过很可惜这个类型中并没有任何有设置窗口相关的属性(比如:宽,高,背景色等等,另外也没法通过修改Style来修改样式),很明显Maui是一个跨平台的设计,因为在移动端并不存在所谓的窗口大小概念,通常打开都是全屏。如果我们需要对窗体进行修改,那么需要拿到Window对象后面管理的Native对象才行

获取Native对象

  • 方法1:注册Maui提供的生命周期函数

在不同的平台会推送相关的程序生命周期通知(在这里可以获取到平台相关操作对象包括对应的ApplicationWindow),使用这个方式存在一些弊端就是当使用多窗体方案时,你没法定位哪个是主窗体(当然第一个创建的必然就是主窗体了),详情请看:应用生命周期 - .NET MAUI | Microsoft Docs[3](这里不做过多探讨如果你像知道细节可以看这个视频:.NET MAUI BLAZOR 生命周期_哔哩哔哩_bilibili[4]

  • 方法2:访问Window下的Handler属性

Maui Window类型中存在这样一个属性Handler(类型是IElementHandler,实现类型是ElementHandler)(所有的Maui控件对象都存在这个个属性),该属性中记录了平台的Native映射对象(如果你希望修改native对象的外观,可以访问他下属的属性PlatformView(将其转换成对应平台的native对象))(注意在刚开始new Window对象时Handler对象并不存在,你可以注册HandlerChanged事件捕获他的变化)(在Winodw平台PlatformView对象是Microsoft.UI.Xaml.Window类型)

学习必要的Winui3相关知识

Winui开始微软带来了窗口的全新设计,如果需要实现诸如窗口大小修改,标题栏修改,全屏实现等等功能你需要学习如下知识:

  • 自定义标题栏

链接:标题栏自定义 - Windows apps | Microsoft Docs[5]

  • AppWindow

这是Win10之后引入的窗口操作对象,学习链接:使用 AppWindow 类显示应用的辅助窗口 - Windows apps | Microsoft Docs[6]以及AppWindow Class (Microsoft.UI.Windowing) - Windows App SDK | Microsoft Docs[7]

注意:官网相关的学习资料在不同的文档中介绍存在偏差,主要是部分设计是老设计,尚未及时更新,请以Windows App SDK 1.1版本为准

通过学习以上知识,我们可以进行部分功能定制

  1. 更改窗口尺寸:

var winuiWindow = Window.Handler?.PlatformView as MicrosoftuiXaml.Window;if (winuiWindow is null)return;var appWindow = winuiWindow.GetAppWindow();if (appWindow is null)return;var displyArea = MicrosoftuiWindowing.DisplayArea.Primary;double scalingFactor = winuiWindow.GetDisplayDensity();var width = 800 * scalingFactor;var height = 600 * scalingFactor;double startX = (displyArea.WorkArea.Width - width) / 2.0;double startY = (displyArea.WorkArea.Height - height) / 2.0;appWindow.MoveAndResize(new((int)startX, (int)startY, (int)width, (int)height), displyArea);
  1. 最大化(使用Win32消息):

var winuiWindow = Window.Handler?.PlatformView as MicrosoftuiXaml.Window;if (winuiWindow is null)return;var windowHanlde = winuiWindow.GetWindowHandle();User32.PostMessage(windowHanlde, WindowMessage.WM_SYSCOMMAND, new IntPtr((int)SysCommands.SC_MINIMIZE), IntPtr.Zero);
  1. 最小化(使用Win32消息):

var winuiWindow = Window.Handler?.PlatformView as MicrosoftuiXaml.Window;if (winuiWindow is null)return;var windowHanlde = winuiWindow.GetWindowHandle();User32.PostMessage(windowHanlde, WindowMessage.WM_SYSCOMMAND, new IntPtr((int)SysCommands.SC_MINIMIZE), IntPtr.Zero);
  1. 全屏:

var winuiWindow = Window.Handler?.PlatformView as MicrosoftuiXaml.Window;if (winuiWindow is null)return;var appWindow = winuiWindow.GetAppWindow();if (appWindow is null)return;//注意由于Maui默认开启了扩展TitleBar(标题栏融合模式?)所以先要去掉 否则全屏仍然会出现 关闭等按钮//虽然关闭了标题栏融合模式,但是全屏时仍然会存在一个类似标题栏的东西,如果需要处理需要进行深度定制(可以查看我的github项目)winuiWindow.ExtendsContentIntoTitleBar = false;appWindow.SetPresenter(MicrosoftuiWindowing.AppWindowPresenterKind.FullScreen);
  1. 修改Maui默认标题栏颜色:

var winuiWindow = Window.Handler?.PlatformView as MicrosoftuiXaml.Window;if (winuiWindow is null)return;var application = MicrosoftuiXaml.Application.Current;var res = application.Resources;//看到这里你一定会疑惑为什么是这样,如果你有兴趣,可以查阅Winui3的源码res["WindowCaptionBackground"] = new MicrosoftuixmlMedia.SolidColorBrush(Microsoftui.Colors.Red);//修改标题栏后需要主动刷新才会生效(否则需要你人为进行一次最小化处理)TriggertTitleBarRepaint();

以上Demo都已经上传Github 地址:WPFDevelopersOrg/Demo[8] ,请查阅MauiApp1这个demo

最后放一个目前我已经实现的Maui Win11的演示效果:

该项目已上传github地址:WPFDevelopersOrg/MauiToolkit[9]

参考资料

[1]

.NET MAUI 跨平台开发合集_哔哩哔哩_bilibili: https://www.bilibili.com/video/BV1VW4y1k7Bk?p=3

[2]

零食栏 - .NET MAUI Community Toolkit - .NET Community Toolkit | Microsoft Docs : https://docs.microsoft.com/zh-cn/dotnet/communitytoolkit/maui/alerts/snackbar

[3]

应用生命周期 - .NET MAUI | Microsoft Docs: https://docs.microsoft.com/zh-cn/dotnet/maui/fundamentals/app-lifecycle

[4]

.NET MAUI BLAZOR 生命周期_哔哩哔哩_bilibili: https://www.bilibili.com/video/BV1vA4y1d74A?spm_id_from=333.999.0.0

[5]

标题栏自定义 - Windows apps | Microsoft Docs: https://docs.microsoft.com/zh-cn/windows/apps/develop/title-bar?tabs=winui3

[6]

使用 AppWindow 类显示应用的辅助窗口 - Windows apps | Microsoft Docs: https://docs.microsoft.com/zh-cn/windows/apps/design/layout/app-window

[7]

AppWindow Class (Microsoft.UI.Windowing) - Windows App SDK | Microsoft Docs: https://docs.microsoft.com/zh-CN/windows/windows-app-sdk/api/winrt/microsoft.ui.windowing.appwindow?view=windows-app-sdk-1.1

[8]

WPFDevelopersOrg/Demo: https://github.com/WPFDevelopersOrg/Demo

[9]

WPFDevelopersOrg/MauiToolkit: https://github.com/WPFDevelopersOrg/MauiToolkit

Maui学习之路(三)--Winui3深入探讨相关推荐

  1. Maui学习之路(一)--Windows窗体设置

    Maui的学习之路 作为 Maui的先行者,我有话要说,微软你为了让我成为牛 B 的程序员真的是煞费苦心,你一定是觉得我不够牛逼所以针对我,存心想气死我. 好了废话不多说,Maui现在也算是正式发布了 ...

  2. Redis——学习之路三(初识redis config配置)

    我们先看看config 默认情况下系统是怎么配置的.在命令行中输入 config get *(如图) 默认情况下有61配置信息,每一个命令占两行,第一行为配置名称信息,第二行为配置的具体信息. 我们就 ...

  3. typescript学习之路(三) —— ts定义类的方法(包含es5以及es6的定义类)

    提起类,不得不说一下,强类型编程语言,如php,java,c++等都有类的概念.而js作为一门弱类型语言,是没有类这个概念的,虽然也能模拟类的实现,但总归不是类.so,ts也只是模拟类而已,使得更贴切 ...

  4. 函数式编程学习之路(三)

    入门: 函数式编程之艰难,在于这玩意更接近数学,就是数学之"用",大牛们在云端,玩纯数学去了,弄出一堆公式及概念,码农们爬在地上,辛苦耕耘,要的是看得见摸得着的,函数式编程就是要打 ...

  5. ZYNQ学习之路(三):自定义IP实现PL处理PS写入BRAM的数据

    目录 一.实验简介 二.vivado部分处理 三.SDK编程 四.实验测试 五.总结 一.实验简介 ZYNQ系列嵌入式FPGA可以使PS将数据写入PL部分BRAM,PL可以将数据读取后再重新写入BRA ...

  6. Cocos2d学习之路三(使用Zwoptex创建精灵表单和CCAnimate动画)

    创建精灵表单: 创建动画先要把图片整合到一个图片上然后生成plist文件: 方法下载Zwoptex软件:http://www.zwopple.com/zwoptex/ 然后打开选择 create ne ...

  7. 学习之路三十一:Varchar和NVarchar的理解

    前段时间在测试的时候发现了一个问题,看过Log之后发现在插入数据到数据库的时候发生异常了! 原因是由于插入的字符串太长,项目中的用到的类型是NVARCHAR,下面就是对它们的理解: 1.VARCHAR ...

  8. MongoDB学习之路(三)

    数据库 一个MongoDB可以建立多个数据库. MongoDB的默认数据库为"db",该数据库存储在data目录中. MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自 ...

  9. Object-c学习之路三(@class与#import的区别)

    //@class只是为了声明B是一个类  当两个类相互包含的时候#import是做不到的 //一般在.h文件中用@class声明一个类成员 在..m文件中具体用到时才用#import应用 //二者区别 ...

最新文章

  1. iOS 数字滚动 类似于老 - 虎- 机的效果
  2. iOS 修改网络图片的大小 宽和高
  3. css 动态rem_【面试题】CSS知识点整理(附答案)
  4. 37镇魔曲网页版服务器状态,37镇魔曲网页版各职业攻略分析
  5. PMCAFF微课堂 | 京东核心团队揭秘:业务增长10倍背后的敏捷开发秘籍
  6. Codeforces Round #285 (Div. 2) D. Misha and Permutations Summation 康托展开 + 线段树
  7. java哪个城市的需求量大_4大互联网热门城市Java薪资情况,看完你想去哪个城市发展呢?...
  8. 牛客网——华为机试(题8:合并表记录)(Java)
  9. fastjson版本_Fastjson高危漏洞风险提示
  10. 转载 Microsoft .NET Pet Shop 4 架构与技术分析
  11. MySQL语句语法参考
  12. Hadoop2.6.0配置參数查看小工具
  13. android 蓝牙 录音,Android 实现蓝牙录音
  14. matlab 打开文件bin
  15. word 2010中页码从任意页开始
  16. 最新消息:原谷歌中国副院长刘骏任职人民搜索首席科学家
  17. 使用腾讯云轻量应用服务器搭建视频直播服务器
  18. 日志库EasyLogging++学习系列(8)—— Verbose日志详解
  19. synctoy 远程同步_使用SyncToy将任何文件夹同步到Dropbox
  20. Apollo星火计划学习笔记——参考线平滑算法解析及实现(以U型弯道场景仿真调试为例)

热门文章

  1. eHR案例|融信:人力资源数字化转型实践
  2. python 多进程并发 阻塞_python并发编程之多进程理论部分
  3. PR 和 MR 的关联
  4. apqp过程流程图范本_APQP项目资料清单excel格式(全套)
  5. 华氏温度与摄氏温度对照表的打印
  6. MacOS忘记密码又一解决方法
  7. 达观数据与西南财经大学金融科技国际联合实验室达成产学研战略合作,共同助推人工智能在财经领域的应用与发展
  8. SOFM-Matlab实例
  9. 从阿尔法本质和三种类型的阿尔法策略谈起
  10. 无人值守,智能变电站可视化管控系统