【Maui】动态菜单实现(绑定数据视图)

前言

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

.NET MAUI 是一款开放源代码应用,是 Xamarin.Forms 的进化版,从移动场景扩展到了桌面场景,并从头重新生成了 UI 控件,以提高性能和可扩展性。 如果以前使用过 Xamarin.Forms 来生成跨平台用户界面,那么你会注意到它与 .NET MAUI 有许多相似之处。 但也有一些差异。 通过使用 .NET MAUI,可使用单个项目创建多平台应用,但如果有必要,可以添加特定于平台的源代码和资源。 .NET MAUI 的主要目的之一是使你能够在单个代码库中实现尽可能多的应用逻辑和 UI 布局。

一、问题描述

实现如下效果,菜单根据数据库取数,自动加载。
在这里插入图片描述

二、解决方案

创建数据模型
UserMenu.cs 用户功能菜单,功能字、导航页面名(后面使用反射可以实例化窗体)、图标名。
UserMenu.cs 用户模块菜单,模块下挂在用户功能菜单。
MenuService.cs 业务逻辑单元,相应事件的处理,菜单数据初始化

三、详细代码

3.1 创建用户菜单模型

二级菜单,功能级别的,UserMenu.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;namespace GlueNet.Mobile.Models
{public class UserMenu{/// <summary>/// 功能名/// </summary>public string Name { get; set; }/// <summary>/// 图标名/// </summary>public string Icon { get; set; }/// <summary>/// 路由名/// </summary>public string Router { get; set; }/// <summary>/// 命令/// </summary>public ICommand Command { get; set; }}
}

3.2 创建用户菜单视图模型

一级菜单,模块级别的,观察者模式需要变更属性,UserMenuViewModel.cs

using GlueNet.Mobile.Models;
using System.ComponentModel;
using System.Runtime.CompilerServices;namespace GlueNet.Mobile.ViewModels
{/// <summary>/// 实现INotifyPropertyChanged接口,观察者模式/// 属性改变通知绑定控件更新/// </summary>public class UserMenuViewModel : INotifyPropertyChanged{/// <summary>/// 模块名/// </summary>private string _moduleName;/// <summary>/// 功能集合/// </summary>private List<UserMenu> _functions;/// <summary>/// 是否展开/// </summary>private bool _isExpanded;/// <summary>/// 展开/收起文本/// </summary>private string _expandedText;public string ModuleName{get => _moduleName;set{_moduleName = value;OnPropertyChanged();}}public List<UserMenu> Functions{get => _functions;set{_functions = value;OnPropertyChanged();}}public bool IsExpanded{get => _isExpanded;set{_isExpanded = value;OnPropertyChanged();}}public string ExpandedText{get => _expandedText;set{_expandedText = value;OnPropertyChanged();}}public event PropertyChangedEventHandler PropertyChanged;protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}
}

3.3 创建用户菜单服务方法

绑定事件、菜单数据初始化。

using GlueNet.Bussiness.Dtos;
using GlueNet.Bussiness;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using System.ServiceModel.Channels;
using System.Windows.Input;
using GlueNet.Mobile.ViewModels;
using GlueNet.Mobile.Models;
using static System.Runtime.InteropServices.JavaScript.JSType;
using System.Xml.Linq;
using System.Diagnostics.Metrics;namespace GlueNet.Mobile.BLL
{public class MenuService : BindableObject{public ObservableCollection<UserMenuViewModel> MenuGroups { get; set; }public ICommand ToggleExpandCommand { get; protected set; }public MenuService(){ToggleExpandCommand = new Command<UserMenuViewModel>(OnToggleExpand);GetMenuData();}private void OnToggleExpand(UserMenuViewModel menuGroup){if (menuGroup != null){menuGroup.IsExpanded = !menuGroup.IsExpanded;menuGroup.ExpandedText = menuGroup.IsExpanded ? "收起" : "展开";OnPropertyChanged(nameof(MenuGroups));}}/// <summary>/// 获取菜单数据,从MES服务端获取/// </summary>public void GetMenuData(){MenuGroups = new ObservableCollection<UserMenuViewModel>{new UserMenuViewModel{ModuleName = "质量管理",Functions = new List<UserMenu>{new UserMenu { Name = "质量1", Icon = "icon_quality.png", Router ="MO2001Page", Command = new Command(() => NavigateToPage("MO2001Page")) } ,new UserMenu { Name = "质量2", Icon = "icon_quality.png", Router = "MO2001Page",Command = new Command(() => NavigateToPage("MO2001Page")) },new UserMenu { Name = "质量3", Icon = "icon_quality.png", Router = "MO2001Page" ,Command = new Command(() => NavigateToPage("MO2001Page"))},new UserMenu { Name = "质量4", Icon = "icon_quality.png", Router = "MO2001Page" ,Command = new Command(() => NavigateToPage("MO2001Page"))},new UserMenu { Name = "质量5", Icon = "icon_quality.png", Router = "MO2001Page" ,Command = new Command(() => NavigateToPage("MO2001Page"))},new UserMenu { Name = "质量6", Icon = "icon_quality.png", Router = "MO2001Page" ,Command = new Command(() => NavigateToPage("MO2001Page"))},new UserMenu { Name = "质量7", Icon = "icon_quality.png", Router = "MO2001Page" ,Command = new Command(() => NavigateToPage("MO2001Page"))},new UserMenu { Name = "质量8", Icon = "icon_quality.png", Router = "MO2001Page" ,Command = new Command(() => NavigateToPage("MO2001Page"))},new UserMenu { Name = "质量9", Icon = "icon_quality.png", Router = "MO2001Page" ,Command = new Command(() => NavigateToPage("MO2001Page"))},},IsExpanded = true,ExpandedText = "收起"},new UserMenuViewModel{ModuleName = "采购管理",Functions = new List<UserMenu>{new UserMenu { Name = "采购1", Icon = "icon_supply.png", Router="MO2001Page", Command = new Command(() => NavigateToPage("MO2001Page")) } ,new UserMenu { Name = "采购2", Icon = "icon_supply.png", Router = "MO2001Page",Command = new Command(() => NavigateToPage("MO2001Page")) },new UserMenu { Name = "采购3", Icon = "icon_supply.png", Router = "MO2001Page" ,Command = new Command(() => NavigateToPage("MO2001Page"))},},IsExpanded = true,ExpandedText = "收起"},new UserMenuViewModel{ModuleName = "作业管理",Functions = new List<UserMenu>{new UserMenu { Name= "栈板下线", Icon= "icon_operation.png", Router="MO1001Page",Command = new Command(() => NavigateToPage("MO1001Page"))},new UserMenu { Name = "次件退库", Icon = "icon_operation.png", Router = "MO1002Page",Command = new Command(() => NavigateToPage("MO1002Page")) }},IsExpanded = true,ExpandedText = "收起"}};}/// <summary>/// 使用反射,根据页面名称导航到指定页面/// </summary>/// <param name="pageName"></param>/// <exception cref="ArgumentException"></exception>private async void NavigateToPage(string pageName){// 获取对象名Type pageType = Type.GetType($"GlueNet.Mobile.Pages.{pageName}");if (pageType != null){//创建实例Page page = (Page)Activator.CreateInstance(pageType);await Application.Current.MainPage.Navigation.PushAsync(page);}else{throw new ArgumentException($"无法导航页面: {pageName}");}}}
}

3.4 创建用户菜单界面

xaml前段界面,需要使用模型绑定,和CollectionView遍历,创建MenuView.xaml。

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:local="clr-namespace:GlueNet.Mobile.BLL"x:Class="GlueNet.Mobile.MenuView"><!--绑定上下文--><ContentView.BindingContext><local:MenuService /></ContentView.BindingContext><!--绑定字体资源,图标已经生成字体库--><ContentView.Resources><Style x:Key="NavButtonStyle" TargetType="RadioButton"><Setter Property="ControlTemplate"><ControlTemplate><Grid><Grid.RowDefinitions><RowDefinition/><RowDefinition Height="30" /></Grid.RowDefinitions><!--替换为图标--><Label Text="{TemplateBinding Value}" FontFamily="Iconfont" FontSize="30" HorizontalOptions="Center"VerticalOptions="Center"></Label><!--替换为文字--><Label Text="{TemplateBinding Content}" Grid.Row="1" HorizontalOptions="Center"VerticalOptions="Center" FontSize="13"></Label></Grid></ControlTemplate></Setter></Style></ContentView.Resources><ScrollView><StackLayout><CollectionView ItemsSource="{Binding MenuGroups}"><CollectionView.ItemTemplate><DataTemplate><StackLayout><!-- 模块名 --><Frame BorderColor="Gray" CornerRadius="5" Padding="5" Margin="5"><Grid ColumnDefinitions="*,60"><Label Text="{Binding ModuleName}" FontSize="Medium" FontAttributes="Bold" VerticalTextAlignment="Center"/><Button Grid.Column="1" Text="{Binding ExpandedText}" Command="{Binding Source={RelativeSource AncestorType={x:Type local:MenuService}}, Path=ToggleExpandCommand}" CommandParameter="{Binding .}" /></Grid></Frame><!-- 功能列表 --><StackLayout IsVisible="{Binding IsExpanded}"><CollectionView ItemsSource="{Binding Functions}" ItemsLayout="VerticalGrid,4"><CollectionView.ItemTemplate><DataTemplate><Grid Padding="5"><Grid.RowDefinitions><RowDefinition Height="*" /><RowDefinition Height="Auto" /></Grid.RowDefinitions><Frame BorderColor="LightGray" CornerRadius="5" Padding="10" Margin="5"><StackLayout Orientation="Vertical" HorizontalOptions="Center" VerticalOptions="Center" ><ImageButton Source="{Binding Icon}" HorizontalOptions="Center" Command="{Binding Command}" /><Label Text="{Binding Name}" FontSize="Medium" VerticalOptions="Center" HorizontalOptions="Center" Margin="10,0,0,0" /></StackLayout></Frame></Grid></DataTemplate></CollectionView.ItemTemplate></CollectionView></StackLayout></StackLayout></DataTemplate></CollectionView.ItemTemplate></CollectionView></StackLayout></ScrollView>
</ContentView>

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

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

相关文章

FreePBX 17 on ubuntu24 with Asterisk 20

版本配置&#xff1a; FreePBX 17&#xff08;最新&#xff09; Asterisk 20&#xff08;最新Asterisk 22&#xff0c;但是FreePBX 17最新只支持Asterisk 21&#xff0c;但是21非LTS版本&#xff0c;所以选择Asterisk 20&#xff09; PHP 8.2 Maria DB (v10.11) Node J…

with as提高sql的执行效率

实战sql with cte(UNIT_ID, UNIT_NAME, PARENT_UNIT_ID, UNIT_CODE ) as (select UNIT_ID, UNIT_NAME, PARENT_UNIT_ID , UNIT_CODEfrom HPFM_UNITunion allselect t.UNIT_ID, t.UNIT_NAME, t.PARENT_UNIT_ID, t.UNIT_CODEfrom HPFM_UNIT tjoin cte on t.PARENT_UNIT_ID cte.U…

G-Star Landscape 2.0 重磅发布,助力开源生态再升级

近日&#xff0c;备受行业瞩目的 G-Star Landscape 迎来了其 2.0 版本的发布&#xff0c;这一成果标志着 GitCode 在开源生态建设方面又取得了重要进展。 G-Star Landscape仓库链接&#xff1a; https://gitcode.com/GitCode-official-team/G-Star-landscape 2024 GitCode 开…

如何在 Linux系统用中挂载和管理磁盘分区

在 Linux 系统中&#xff0c;挂载和管理磁盘分区是系统管理的基本任务之一。以下是详细步骤&#xff0c;帮助你完成这一过程。 1. 查看现有磁盘和分区 首先&#xff0c;使用以下命令来查看系统中的磁盘和分区&#xff1a; bash 复制 lsblk或者使用&#xff1a; bash 复制…

Unity:删除注册表内的项目记录

然后WinR按键输入regedit 打开注册表 在注册表 HKEY CURRENT USER—>SOFTWARE—>Unity—>UnityEditor—>DefaultCompany —>language_Test 中&#xff0c;删除我们的之前存储的语言环境数据。在 “ 三、文本调用和替换 ” 测试时已经将语言环境存储到注册表中了…

Zustand selector 发生 infinate loops的原因以及解决

Zustand selector 发生 infinate loops 做zustand tutorial project的时候&#xff0c;使用选择器方法引入store&#xff0c;出现Maximum update depth exceeded,也就是组件一直重新渲染&#xff0c;改成直接使用store就没有不会出现这个问题。如下&#xff1a; // const [xIs…

世优波塔数字人 AI 大屏再升级:让智能展厅讲解触手可及

近日&#xff0c;世优波塔大屏AI数字人再度升级&#xff0c;将数字人技术与大屏交互推向了新的高度&#xff0c;为用户带来了全方位的卓越体验&#xff0c;让人工智能不断重塑我们的生活与工作方式。 新形象&#xff1a;数字人的独特魅力 高精度的数字人形象一直是波塔智能体…

STM32F4分别驱动SN65HVD230和TJA1050进行CAN通信

目录 一、CAN、SN65HVD230DR二、TJA10501、TJA1050 特性2、TJA1050 引脚说明 三、硬件设计1、接线说明2、TJA1050 模块3、SN65HVD230 模块 四、程序设计1、CAN_Init&#xff1a;CAN 外设初始化函数2、CAN_Send_Msg、CAN_Receive_Msg 五、功能展示1、接线图2、CAN 数据收发测试 …

Redis数据库笔记——主从复制

大家好&#xff0c;这里是Good Note&#xff0c;关注 公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍Redis的主从复制模式&#xff0c;包括作用&#xff0c;原因&#xff0c;工作原理&#xff0c;同步流程等。 文章目录 主从复制什么是 Redis 主从…

【Unity功能集】TextureShop纹理工坊(十二)画笔工具、橡皮擦工具

项目源码:在终章发布 索引 画笔工具橡皮擦工具PS画笔工具、橡皮擦工具TextureShop画笔工具绘制点绘制线段画笔逻辑TextureShop橡皮擦工具画笔工具 画笔工具,可在绘画板上进行自由绘画的工具(了解PS画笔工具)。 橡皮擦工具 橡皮擦工具,可在绘画板上进行自由擦除颜色的工…

MMDetection框架下的常见目标检测与分割模型综述与实践指南

目录 综述与实践指南 SSD (Single Shot MultiBox Detector) 基本配置和使用代码 RetinaNet 基本配置和使用代码 Faster R-CNN 基本配置和使用代码 Mask R-CNN 基本配置和使用代码 Cascade R-CNN 基本配置和使用代码 总结 综述与实践指南 MMDetection是一个基于Py…

【数据库系统概论】第5章 数据库完整性【!触发器】

目录 5.1数据库完整性概述 5.2 实体完整性 5.3 参照完整性 5.4 用户定义的完整性 属性上的约束 1. 列值非空&#xff08;NOT NULL&#xff09; 2. 列值唯一&#xff08;UNIQUE&#xff09; 3. 检查列值是否满足条件&#xff08;CHECK&#xff09; 元组上的约束 5.5 完…

rk3568 , buildroot , qt ,使用sqlite, 动态库, 静态库

问题说明&#xff1a; 客户反馈 &#xff0c;buildroot 系统 &#xff0c;使用qt 使用sqlite &#xff0c;有报错&#xff0c;无法使用sqlite. 测试情况说明&#xff1a; 我自己测试&#xff0c;发现&#xff0c; buildroot 自己默认就是 使能了 sqlite 的。 是否解决说明&…

机器学习实战——决策树:从原理到应用的深度解析

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​​​ ​​​ ​​ 决策树&#xff08;Decision Tree&#xff09;是一种简单而直观的分类与回归模型&#xff0c;在机器学习中广泛应用。它的…

MySQL 如何赶上 PostgreSQL 的势头?

原文地址 我与 MySQL 社区的前辈交谈时&#xff0c;经常遇到这个问题&#xff1a;「为什么 MySQL 这么棒&#xff0c;而且&#xff08;至少根据 DB-Engines 的计算&#xff09;仍然比 PostgreSQL 更流行&#xff1b;但它的地位在下降&#xff0c;PostgreSQL 却势不可挡地越来越…

Linux 下信号的保存和处理

信号的几个状态 信号抵达: 当接收到的信号被处理时, 此时就成为信号的抵达信号的未决: 从信号的产生到信号抵达这个时间段之间, 称为信号未决信号阻塞: 当进程设置了某个信号为阻塞后, 这个进程就不会在接收到这个信号信号忽略: 将信号设置为忽略后, 接收到这个信号, 对这个信…

mybatisX插件的使用,以及打包成配置

装mybatisX插件&#xff1b; idea连接数据库&#xff1b; 点击mybatisx-generator&#xff0c;设置自己装mybatisX插件&#xff1b; idea连接数据库&#xff1b; 点击mybatisx-generator&#xff0c;设置自己要的包和类&#xff1b; 如果要把自己的配置设置成一个自定义模板&a…

AAAI2023《Controllable Image Captioning via Prompting》

摘要 文章提出了一种通过提示学习&#xff08;prompt learning&#xff09;嵌入到图像描述生成框架中的方法&#xff0c;以实现对图像描述的可控生成。具体来说&#xff0c;设计了一组提示来微调预训练的图像描述生成器&#xff0c;这些提示使模型能够吸收来自不同领域的风格化…

AR 眼镜之-拍照/录像动效切换-实现方案

目录 &#x1f4c2; 前言 AR 眼镜系统版本 拍照/录像动效切换 1. &#x1f531; 技术方案 1.1 技术方案概述 1.2 实现方案 1&#xff09;第一阶段动效 2&#xff09;第二阶段动效 2. &#x1f4a0; 默认代码配置 2.1 XML 初始布局 2.2 监听滑动对 View 改变 3. ⚛️…

kubeneters-循序渐进Cilium网络(二)

文章目录 概要IP 地址配置接口配置解析结论 概要 接续前一章节&#xff0c;我们还是以这张图继续深入Cilium网络世界 IP 地址配置 通过检查 Kubernetes 集群的当前环境&#xff0c;可以获取实际的 IP 地址和配置信息。这些信息将被补充到之前的网络示意图中&#xff0c;以使…