Maui学习之路(三)--Winui3深入探讨

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]

188efb04ff5345196dc3045277f8d148.png

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

613382312ab73049d9c6a7ec24e6a05b.png
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

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

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

相关文章

centos 7.1 apache 源码编译安装

Apache编译安装 一&#xff0c;需要软件&#xff1a; http://mirrors.cnnic.cn/apache//apr/apr-1.5.2.tar.gz 1.apr-1.5.2.tar.gz http://mirrors.cnnic.cn/apache//apr/apr-util-1.5.4.tar.gz 2.apr-util-1.5.4.tar.gz http://exim.mirror.fr/pcre/pcre-8.38.tar.gz 3.pcre-8…

【ArcGIS风暴】ArcGIS平台上点云(.las)数据生成等高线方法案例精解

las是点云数据常见的存储格式,摄影测量和激光雷达数据均采用此格式,点云数据常用来生成等高线,地籍测量,土方量计算等。本文讲解在ArcGIS平台上生成等高线并转换为dwg格式供CASS使用。 扩展阅读: 什么是点云?什么是Las数据集?一篇文章告诉你点云数据的奥秘 ArcGIS+CASS点…

通过两级网关设计来路由服务网格流量

编者的话本文是来自笔者的公司 Tetrate[1] 工程师 Petr McAllister 的分享&#xff0c;Tetrate 的拳头产品是 Tetrate Service Bridge[2]&#xff08;下文简称 TSB&#xff09;&#xff0c;它是在开源的 Istio 和 Envoy 基础上构建的&#xff0c;但为其增加了管理平面。简介Tet…

各个线程顺序循环执行

问题描述&#xff1a;A任务执行完之后执行B任务&#xff0c;B任务执行之后再执行C任务&#xff0c;C任务执行完之后A再执行任务&#xff0c;以此循环下去 Task 1 package com.ydd.work.concurrent;2 3 import java.util.concurrent.atomic.AtomicInteger;4 /**5 * 6 * author…

python类相关

class A:def bar(self):print("BAR")self.f1() class B(A):def f1(self):print("B") class C:def f1(self):print("C") class D(C,B):pass obj D() obj.bar() # 创建了类A、B、C、D&#xff1b; # D继承了C和B&#xff0c;B继承了A&#xff0c;…

Python File 介绍

Open() 方法 Python open() 方法用于打开一个文件&#xff0c;并返回文件对象&#xff0c;在对文件进行处理过程都需要使用到这个函数&#xff0c;如果该文件无法被打开&#xff0c;会抛出 OSError。 注意&#xff1a;使用 open() 方法一定要保证关闭文件对象&#xff0c;即调用…

H5开发中常用的js方法

2019独角兽企业重金招聘Python工程师标准>>> h5和app之间的webview交互 这是常用的交互方法之一&#xff0c;iOS可以使用WKWebView,安卓可以使用JsBridge,完成常见的交互效果。function webViewHandler(iosCallback, adrCallback) {if (getMobileOperatingSystem() …

【前端优化】

如何进行前端优化 &#xff08;1&#xff09; 减少http 请求次数&#xff1a;css spirit&#xff08;多张小图放一个大图上&#xff0c;用定位选择不同小图&#xff09;,data uri&#xff08;压缩图片大小&#xff09;&#xff0c; 图片大小控制合适&#xff1b;网页Gzip&#…

GPS RTK(银河1)基准站架设、移动站设置完整操作流程

本文讲解GPS RTK(银河1)基站架设完整操作流程,包括相对坐标、点校正等操作。 文章目录 一、架设基准站二、启动基准站三、架设移动站四、设置移动站一、架设基准站 基准站一定要架设在视野比较开阔,周围环境比较空旷的地方,地势比较高的地方;避免架在高压输变电设备附近…

在.NET 6.0上使用Kestrel配置和自定义HTTPS

本章是《定制ASP NET 6.0框架系列文章》的第四篇。在本章&#xff0c;我们将学习ASP.NET Core的Kestrel配置和自定义HTTPS&#xff0c;好我们开始正文。在ASP.NET Core中&#xff0c;默认情况下HTTPS处于打开状态&#xff0c;这个不是问题&#xff0c;我们无需禁用它。因为如果…

dom4j-2.1.1 jaxen-1.1.6 读取xml数据源

<?xml version"1.0" encoding"UTF-8"?> <data><row><id>1</id><name>JackieChen</name></row><row><id>2</id><name>TomLee</name></row> </data> package…

Virtualbox安装增强工具失败

在安装Virtualbox增强工具安装时出现unable to find the sources of your current Linux kernel&#xff0c;安装失败&#xff0c;导致主机与虚拟机之间不能共享文件夹&#xff0c;不能复制粘贴&#xff0c;鼠标也不能直接移动到物理机&#xff0c;需要按快捷键才行。 解决办法…

C语言试题118之求1到20的每个数的阶层之和

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 题目:求 1+2!+3!+…+20!的和 分析:此程序只是把累加变成了累乘。 2 、温馨提示 想获取更多…

吐血整理:C#顺序、选择、循环结构用法与案例,这一篇就够了!

C#语言中用于结构化程序设计的三种基本结构是:顺序结构、选择结构、循环结构。本文详细整理了以上三种结构的用法,案例。 文章目录 4.1 顺序结构4.1.1 赋值语句4.1.2 输入语句4.1.3 输出语句4.1.4 复合语句4.1.5 应用实例4.2 选择结构4.2.1 if条件语句4.2.2 switch结构4.3 循…

java.lang.NoSuchFieldError: EMPTY_ORDERED_ITERATOR起因及解决办法

java.lang.NoSuchFieldError: EMPTY_ORDERED_ITERATOR 最近这个错误遇到了好多次&#xff0c;不过都很轻松的解决了&#xff0c;问题的起因是多了一个collection包&#xff0c;如下图 看到了&#xff0c;只要把其中的一个删除掉&#xff0c;更新启动Tomcat就行了。 本文转自suc…

由ASP.NET Core根据路径下载文件异常引发的探究

前言最近在开发新的项目&#xff0c;使用的是ASP.NET Core6.0版本的框架。由于项目中存在文件下载功能&#xff0c;没有使用类似MinIO或OSS之类的分布式文件系统&#xff0c;而是下载本地文件&#xff0c;也就是根据本地文件路径进行下载。这其中遇到了一个问题&#xff0c;是关…

[转]EL函数、自定义EL函数、自定义标签

EL函数 1、EL函数的作用&#xff1a;操作字符串 2、在JSP页面中要引入EL函数库 <% taglib prefix"fn" uri"http://java.sun.com/jsp/jstl/functions" %> 3、语法 ${ fn:方法名(参数) } 4、实例 <% page language"java" contentTyp…

XidianOJ 1019 自然数的秘密

题目描述 题意&#xff1a; 已知&#xff1a;N&#xff01;N*(N-1)*...*2*1 找到最小自然数 N, 使N!末尾有连续 M个零. 例如, 5! 的结尾包含1个零. 输入 第一行输入一个整数T,表示有T组测试数据。 对于每组测试数据&#xff0c;输入一个整数M&#xff0c;表示包含M个零。&#…

C语言试题119之利用递归方法求 5的阶层

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 题目:利用递归方法求 5的阶层 分析:递归公式:fn=fn_1*4的阶层 2 、温馨提示 想获取更多C…

深入学习http协议(转)

http://www.blogjava.net/zjusuyong/articles/304788.html转载来的&#xff0c;没看到原文地址。http协议学习系列1. 基础概念篇1.1 介绍HTTP是Hyper Text Transfer Protocol&#xff08;超文本传输协议&#xff09;的缩写。它的发展是万维网协会&#xff08;World Wide Web Co…