【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.mzph.cn/web/65945.shtml

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

相关文章

RNN之:LSTM 长短期记忆模型-结构-理论详解-及实战(Matlab向)

0.前言 递归&#xff01;循环神经网络Recurrent Neural Network 循环神经网络&#xff08;又称递归神经网络&#xff0c;Recurrent Neural Network&#xff0c;RNN&#xff09;。是一种用于处理序列数据的神经网络结构&#xff0c;具有记忆功能&#xff0c;能够捕捉序列中的时…

泛目录和泛站有什么差别

啥是 SEO 泛目录&#xff1f; 咱先来说说 SEO 泛目录是啥。想象一下&#xff0c;你有一个巨大的图书馆&#xff0c;里面的书架上摆满了各种各样的书&#xff0c;每一本书都代表着一个网页。而 SEO 泛目录呢&#xff0c;就像是一个超级图书管理员&#xff0c;它的任务就是把这些…

【Vue】全局/局部组件使用流程(Vue2为例)

全局组件和局部组件区别 如何使用 全局组件&#xff1a;全局注册后&#xff0c;可以在任意页面中直接使用。局部组件&#xff1a;在页面中需要先导入子组件路径&#xff0c;注册组件才能使用。 适用场景 全局组件&#xff1a;适用于高频使用的组件&#xff0c;如导航栏、业…

【Pytorch实用教程】PyTorch 中如何输出模型参数:全面指南

文章目录 PyTorch 中如何输出模型参数:全面指南1. 为什么需要输出模型参数?2. PyTorch 中输出模型参数的方法2.1 使用 `model.parameters()` 输出所有参数2.2 使用 `model.named_parameters()` 输出参数名称和值2.3 使用 `model.state_dict()` 输出模型的参数字典2.4 输出特定…

1、docker概念和基本使用命令

docker概念 微服务&#xff1a;不再是以完整的物理机为基础的服务软件&#xff0c;而是借助于宿主机的性能。以小量的形式&#xff0c;单独部署的应用。 docker&#xff1a;是一个开源的应用容器引擎&#xff0c;基于go语言开发的&#xff0c;使用时apache2.0的协议。docker是…

Genymotion配套VirtualBox所在地址

在 Genymotion打开虚拟机前需要先打开VirtualBox中的虚拟机 C:\Program Files\Oracle\VirtualBox\VirtualBox.exe 再开启genymotion中的虚拟机开关

【Linux】深刻理解软硬链接

一.软硬链接操作 1.软连接 touch 创建一个文件file.txt &#xff0c;对该文件创建对应的软链接改怎么做呢&#xff1f; ln -s file.txt file-soft.link .给对应文件创建软连接。 软连接本质就是一个独立的文件&#xff0c;因为我们对应的软连接有独立的inode&#xff0c;他…

第三十六章 Spring之假如让你来写MVC——拦截器篇

Spring源码阅读目录 第一部分——IOC篇 第一章 Spring之最熟悉的陌生人——IOC 第二章 Spring之假如让你来写IOC容器——加载资源篇 第三章 Spring之假如让你来写IOC容器——解析配置文件篇 第四章 Spring之假如让你来写IOC容器——XML配置文件篇 第五章 Spring之假如让你来写…

快速上手 HarmonyOS 应用开发

一、DevEco Studio 安装与配置 1. DevEco Studio 简介 DevEco Studio 是 HarmonyOS 的一站式集成开发环境&#xff08;IDE&#xff09;&#xff0c;提供了丰富的工具和功能&#xff0c;支持 HarmonyOS 应用开发的全流程。 2. DevEco Studio 下载与安装 下载地址&#xff1a…

Java Web开发进阶——错误处理与日志管理

错误处理和日志管理是任何生产环境中不可或缺的一部分。在 Spring Boot 中&#xff0c;合理的错误处理机制不仅能够提升用户体验&#xff0c;还能帮助开发者快速定位问题&#xff1b;而有效的日志管理能够帮助团队监控应用运行状态&#xff0c;及时发现和解决问题。 1. 常见错误…

图解Git——分支的新建与合并《Pro Git》

⭐分支的新建与合并 先引入一个实际开发的工作流&#xff1a; 开发某个网站。为实现某个新的需求&#xff0c;创建一个分支。在这个分支上开展工作。 正在此时&#xff0c;你突然接到一个电话说有个很严重的问题需要紧急修补。你将按照如下方式来处理&#xff1a; 切换到你…

【数据可视化-12】数据分析岗位招聘分析

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

excel仅复制可见单元格,仅复制筛选后内容

背景 我们经常需要将内容分给不同的人&#xff0c;做完后需要合并 遇到情况如下 那是因为直接选择了整列&#xff0c;当然不可以了。 下面提供几种方法&#xff0c;应该都可以 直接选中要复制区域然后复制&#xff0c;不要选中最上面的列alt;选中可见单元格正常复制&#xff…

支持向量回归(SVR:Support Vector Regression)用于A股数据分析、预测

简单说明 支持向量回归是一种用来做预测的数学方法,属于「机器学习」的一种。 它的目标是找到一条「最合适的线」,能够大致描述数据点的趋势,并允许数据点离这条线有一定的误差(不要求所有点都完全落在这条线上)。 可以把它想象成:找到一条「宽带」或「隧道」,大部分…

LabVIEW水位监控系统

LabVIEW开发智能水位监控系统通过集成先进的传感技术与控制算法&#xff0c;为工业液体存储提供精确的水位调控&#xff0c;保证了生产过程的连续性与安全性。 项目背景 在化工和饮料生产等行业中&#xff0c;水位控制的准确性对保证生产安全和提高产品质量至关重要。传统的水…

深入浅出 Android AES 加密解密:从理论到实战

深入浅出 Android AES 加密解密&#xff1a;从理论到实战 在现代移动应用中&#xff0c;数据安全是不可忽视的一环。无论是用户隐私保护&#xff0c;还是敏感信息的存储与传输&#xff0c;加密技术都扮演着重要角色。本文将以 AES&#xff08;Advanced Encryption Standard&am…

React Fiber框架中的Render渲染阶段——workLoop(performUnitOfWork【beginWork与completeWork】)

触发渲染过程——renderRoot renderRoot 是一个函数&#xff0c;用于触发渲染工作。它通常会调用并递归地执行一系列的渲染任务&#xff0c;直到完成整个更新过程。这个过程包括执行 Fiber 树中的 beginWork 和 completeWork&#xff0c;以及渲染新状态或 DOM。 function ren…

【优先算法】思还故里闾,欲归道无因 - 前缀和

本篇博客给大家带来的是前缀和算法的知识点, 也是一样通过OJ题理解,掌握,应用该算法. &#x1f40e;文章专栏: 算法 &#x1f680;若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅&…

亿道三防丨三防笔记本是什么意思?和普通笔记本的优势在哪里?

三防笔记本是什么意思&#xff1f;和普通笔记本的优势在哪里&#xff1f; 在现代社会中&#xff0c;笔记本电脑已经成为人们工作和生活中不可或缺的一部分。然而&#xff0c;在一些特殊行业或环境中&#xff0c;普通笔记本电脑由于其脆弱性和对环境条件的敏感性&#xff0c;往…

SOME/IP 协议详解——服务发现

文章目录 1. Introduction &#xff08;引言&#xff09;2. SOME/IP Service Discovery (SOME/IP-SD)2.1 General&#xff08;概述)2.2 SOME/IP-SD Message Format2.2.1 通用要求2.2.2 SOME/IP-SD Header2.2.3 Entry Format2.2.4 Options Format2.2.4.1 配置选项&#xff08;Co…