【Maui】视图界面与数据模型绑定

文章目录

  • 前言
  • 一、问题描述
  • 二、解决方案
  • 三、软件开发(源码)
    • 3.1 创建模型
    • 3.2 视图界面
    • 3.3 控制器逻辑层
  • 四、项目展示


前言

.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 布局。

一、问题描述

MVVM模式(Model-View-ViewModel)架构模式,是将View和ViewModel关联起来,通过双向数据绑定实现View和ViewModel的同步更新。View负责展示数据和用户交互,ViewModel负责处理数据和业务逻辑,Model负责存储数据。MVVM的优点是能够降低View和ViewModel之间的耦合,使得代码更加可维护和可测试。
.NET MAUI是如何进行将View和ViewModel双向绑定的呢?

二、解决方案

1、视图–数据模型绑定:定义ViewModels,视图层通过Binding属性绑定ViewModels
2、数据模型–视图绑定:ViewModels属性发生改变,需要通知View进行更新,通知采用观察者模式,更新View采用委托Invoke
听起来很复杂对不对?其实很简单。

三、软件开发(源码)

3.1 创建模型

文件名:TitleBarViewModel.cs
位置:ViewModels
备注:集合一定要定义成 ObservableCollection,不要使用List,否则无法实现MVVM,ObservableCollection实现INotifyCollectionChanged, INotifyPropertyChanged。

using App.Mes.Core.Operation.Services.Mobile;
using Newtonsoft.Json;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace GlueNet.Mobile.ViewModels
{public class TitleBarViewModel : INotifyPropertyChanged{private string _version;private string _workdate;private string _classesValue; //班组private string _userID;private string _userName;private string _userComb; // 用户编号+姓名public ObservableCollection<KeyValuePair<string, string>> ClassesOptions { get; set; } = new ObservableCollection<KeyValuePair<string, string>>();public string ClassesValue{get => _classesValue;set{if (_classesValue != value){_classesValue = value;OnPropertyChanged();}}}public string Version{get => _version;set{_version = value;OnPropertyChanged();}}public string WorkDate{get => _workdate;set{if (_workdate != value){_workdate = value;OnPropertyChanged();}}}public string UserID{get => _userID;set{_userID = value;OnPropertyChanged();}}public string UserName{get => _userName;set{_userName = value;OnPropertyChanged();}}public string UserComb{get => _userComb;set{_userComb = value;OnPropertyChanged();}}/// <summary>/// 构造函数/// </summary>public TitleBarViewModel(){InitializeOptions();}private void InitializeOptions(){//取班组string str_Reason = GycMobileService.Proxy.GetKeyValue("class_group");var ReasonList = JsonConvert.DeserializeObject<List<KeyValuePair<string, string>>>(str_Reason);foreach (var item in ReasonList){ClassesOptions.Add(new KeyValuePair<string, string>(item.Key, item.Value));}ClassesValue = ClassesOptions.FirstOrDefault().Value;}/// <summary>/// 班组/// </summary>public string GetClassesValueByKey(string key){var Classes = ClassesOptions.FirstOrDefault(x => x.Key == key);return Classes.Value;}//实现了INotifyPropertyChanged接口,用于在属性值发生变化时通知界面更新。public event PropertyChangedEventHandler PropertyChanged;//事件委托更新属性protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}
}

文件名:MO1002DetailsModel.cs
位置:ViewModels
备注:集合一定要定义成 ObservableCollection,不要使用List,否则无法实现MVVM,ObservableCollection实现INotifyCollectionChanged, INotifyPropertyChanged。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace GlueNet.Mobile.Models
{public class MO1002DetailsModel{/// <summary>/// 预留申请单主号/// </summary> public virtual string CReservedNo { get; set; }/// <summary>/// 创建人/// </summary> public virtual string Creator { get; set; }/// <summary>/// 创建人/// </summary> public virtual string CreatorCn { get; set; }/// <summary>/// 创建时间/// </summary> public virtual DateTime? CreateTime { get; set; }/// <summary>/// 创建时间/// </summary> public virtual string CreateTimeText { get; set; }/// <summary>/// 单据类型(1 移库 2 领料 3退库)/// </summary> public virtual string CReservedType { get; set; }/// <summary>/// 单据类型(1 移库 2 领料 3退库)/// </summary> public virtual string CReservedTypeCn { get; set; }/// <summary>/// 物料类型  1-散料 2 纸卷(21大纸,22小纸,23纸垛,26tissue半成品) ( 暂不用mtrl_type)/// </summary> public virtual string CMtrlType { get; set; }/// <summary>/// 物料类型  1-散料 2 纸卷(21大纸,22小纸,23纸垛,26tissue半成品) ( 暂不用mtrl_type)/// </summary> public virtual string CMtrlTypeCn { get; set; }/// <summary>/// 发货实体库代码/// </summary> public virtual string CSendStoreHouse { get; set; }/// <summary>/// 发货实体库代码/// </summary> public virtual string CSendStoreHouseCn { get; set; }/// <summary>/// 发货业务工厂代码/// </summary> public virtual string CSendBnPlantId { get; set; }/// <summary>/// 发货业务工厂/// </summary> public virtual string CSendBnPlantIdCn { get; set; }/// <summary>/// 发货班次/// </summary> public virtual string CClassRate { get; set; }/// <summary>/// 备注/// </summary> public virtual string CRemark { get; set; }/// <summary>/// 备注/// </summary> public virtual string CRemarkCn { get; set; }/// <summary>/// 是否被选中/// </summary> public virtual bool IsCheck { get; set; } = false;}
}

3.2 视图界面

文件名:MO1002Page.xaml
位置:Pages
备注:使用Mode=TwoWay,使用双向绑定,可以不设置观察者模式;
遍历中的RadioButton不要使用CheckedChanged()属性,亲测有bug,在2条数据被删除1条数据时,页面自然只剩1条数据,RadioButton会自动被勾选,但是不会触发CheckedChanged(),不建议使用CheckedChanged()属性。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"x:Class="GlueNet.Mobile.Pages.MO1002Page"Title="件次退料"><StackLayout><!--顶部标题栏--><Grid BackgroundColor="{StaticResource Gray300}" Padding="5"><Grid.RowDefinitions><RowDefinition Height="*" /></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="*" /><ColumnDefinition Width="*" /><ColumnDefinition Width="*" /></Grid.ColumnDefinitions><!-- 显示当前日期,左边部分 --><DatePicker x:Name="HiddenDatePicker"Date="{Binding TitleBar.WorkDate}"TextColor="White" Format="yyyy-MM-dd"HorizontalOptions="Start" VerticalOptions="Center" Grid.Column="0" DateSelected="OnDateSelected" /><!-- 显示班组,绑定点击事件 --><Label Text="{Binding TitleBar.ClassesValue}"TextColor="White"HorizontalOptions="Center"VerticalOptions="Center"Grid.Column="1"x:Name="ClassesLabel"><Label.GestureRecognizers><TapGestureRecognizer Tapped="OnClassesClicked" /></Label.GestureRecognizers></Label><!-- 显示登录用户名,绑定点击事件 --><Label Text="{Binding TitleBar.UserName}"TextColor="White"HorizontalOptions="Center"VerticalOptions="Center"Grid.Column="2"x:Name="UserNameLabel"></Label></Grid><!--中部数据区域--><ScrollView VerticalOptions="FillAndExpand"><CollectionView ItemsSource="{Binding DataList}" SelectionMode="None"><CollectionView.ItemTemplate><DataTemplate><HorizontalStackLayout><!--必须要,否则前端有bug--><RadioButton GroupName="DataListGroup" IsChecked="{Binding IsCheck, Mode=TwoWay}"/><Frame BorderColor="LightGray" CornerRadius="5" Padding="10" Margin="5"><Grid ColumnDefinitions="*,*,*,*" RowDefinitions="*,*,*,*,*,*"><Label Grid.Column="0" Text="退库单号:" FontSize="Small" /><Label Grid.Column="1" Grid.ColumnSpan="3" Text="{Binding CReservedNo}" FontSize="Small" /><Label Grid.Row="1" Grid.Column="0" Text="单据类型:" FontSize="Small" /><Label Grid.Row="1" Grid.Column="1" Text="{Binding CReservedTypeCn}" FontSize="Small"/><Label Grid.Row="1" Grid.Column="2" Text="物料类型:" FontSize="Small" /><Label Grid.Row="1" Grid.Column="3" Text="{Binding CMtrlTypeCn}" FontSize="Small"/><Label Grid.Row="2" Grid.Column="0" Text="线边库:" FontSize="Small" /><Label Grid.Row="2" Grid.Column="1" Text="{Binding CSendStoreHouseCn}" FontSize="Small"/><Label Grid.Row="3" Grid.Column="0" Text="业务工厂:" FontSize="Small" /><Label Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" Text="{Binding CSendBnPlantIdCn}" FontSize="Small"/><Label Grid.Row="4" Grid.Column="0" Text="创建人:" FontSize="Small" /><Label Grid.Row="4" Grid.Column="1" Text="{Binding CreatorCn}" FontSize="Small"/><Label Grid.Row="4" Grid.Column="2" Text="创建时间:" FontSize="Small" /><Label Grid.Row="4" Grid.Column="3" Text="{Binding CreateTimeText}" FontSize="Small"/><Label Grid.Row="5" Grid.Column="0" Text="退库原因:" FontSize="Small" /><Label Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="3" Text="{Binding CRemarkCn}" FontSize="Small" /></Grid></Frame></HorizontalStackLayout></DataTemplate></CollectionView.ItemTemplate></CollectionView></ScrollView><!--底部操作栏--><Grid HeightRequest="60"  Padding="5"  BackgroundColor="{StaticResource Gray300}"><Grid.ColumnDefinitions><ColumnDefinition Width="*" /><ColumnDefinition Width="*" /><ColumnDefinition Width="*" /><ColumnDefinition Width="*" /></Grid.ColumnDefinitions><Button HorizontalOptions="Center" Text="刷新"  FontSize="Small" BackgroundColor="LightBlue" Clicked="OnRefreshClicked"/><Button Grid.Column="1" HorizontalOptions="Center" Text="制单"  FontSize="Small" BackgroundColor="Green" Clicked="OnAddClicked"/><Button Grid.Column="2" HorizontalOptions="Center" Text="编辑"  FontSize="Small" BackgroundColor="YellowGreen" Clicked="OnEditClicked"/><Button Grid.Column="3" HorizontalOptions="Center" Text="删除"  FontSize="Small" BackgroundColor="Red" Clicked="OnDeleteClicked"/></Grid></StackLayout></ContentPage>

3.3 控制器逻辑层

定义

   private MO1002AllViewModel MO1002List { get; set; } = new MO1002AllViewModel();

界面绑定,也可以在view层绑定

	BindingContext = MO1002List;

数据初始化,从服务端取数(可以不看,重点关注数据绑定)

    /// <summary>/// 刷新/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private async void OnRefreshClicked(object sender, EventArgs e){try{//按工作日期、制单人查询string str_Result = GycMobileService.Proxy.GetMasterTAX_2010(MO1002List.TitleBar.WorkDate, MO1002List.TitleBar.UserID);var var_MobileResult = JsonConvert.DeserializeObject<MobileResult>(str_Result);string aa = var_MobileResult.RetValue.ToString();if (var_MobileResult.IsSuccess){MO1002List.DataList.Clear();List<Tax2010>? list_Tax2010 = JsonConvert.DeserializeObject<List<Tax2010>>(var_MobileResult.RetValue.ToString());if (list_Tax2010 != null && list_Tax2010.Count > 0){// 创建一个 MO1002AddViewModel 实例来获取线边库的名称var addViewModel = new MO1002AddViewModel();foreach (var item in list_Tax2010){MO1002List.DataList.Add(new MO1002DetailsModel{CReservedNo = item.CReservedNo,Creator = item.Creator,CreatorCn = MO1002List.TitleBar.UserName,//框架未知问题,创建日期数据返回不对CreateTime = item.CreateTime,CreateTimeText = item.CreateTime.ToString("yyyy-MM-dd HH:MM:ss"),//CreateTime = item.LastModifyTime,//CreateTimeText = item.LastModifyTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? string.Empty,CReservedType = item.CReservedType,CReservedTypeCn = "退库",CMtrlType = item.CMtrlType,CMtrlTypeCn = addViewModel.GetMtrlTypeValueByKey(item.CMtrlType),CSendStoreHouse = item.CSendStoreHouse,CSendStoreHouseCn = addViewModel.GetHouseValueByKey(item.CSendStoreHouse),CSendBnPlantId = item.CSendBnPlantId,CSendBnPlantIdCn = addViewModel.GetBnPlantValueByKey(item.CSendBnPlantId),CClassRate = item.CClassRate,CRemark = item.CRemark,CRemarkCn = addViewModel.GetReasonValueByKey(item.CRemark),});}}Toaster.Show(var_MobileResult.Remark);}else{await MessageExtension.Error(var_MobileResult.Remark);}}catch (Exception ex){Toaster.Show(ex.Message);return;}}

获取选中的数据,从集合中取被勾选的数据行。

    /// <summary>/// 单选按钮选中事件/// </summary>/// <param name="sender"></param>/// <param "e"></param>private void OnRadioButtonCheckedChanged(){if (MO1002List.DataList != null && MO1002List.DataList.Count > 0){MO1002List.SelectedDetail = MO1002List.DataList.FirstOrDefault(x => x.IsCheck == true) ?? new MO1002DetailsModel();}}

四、项目展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

从 Spark 到 StarRocks:实现58同城湖仓一体架构的高效转型

作者&#xff1a;王世发&#xff0c;吴艳兴等&#xff0c;58同城数据架构部 导读&#xff1a; 本文介绍了58同城在其数据探查平台中引入StarRocks的实践&#xff0c;旨在提升实时查询性能。在面对传统Spark和Hive架构的性能瓶颈时&#xff0c;58同城选择StarRocks作为加速引擎&…

探秘 Linux 进程状态:解锁系统运行的密码

&#x1f31f; 快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。&#x1f31f; &#x1f6a9;用通俗易懂且不失专业性的文字&#xff0c;讲解计算机领域那些看似枯燥的知识点&#x1f6a9; 在 Linux 系统…

深度学习-89-大语言模型LLM之AI应用开发的基本概念

文章目录 1 什么是智能体(Agent)2 什么是大语言模型(LLM)2.1 LLM的训练及使用2.2 Transformer架构2.3 基于LLM的Agent框架3 什么是检索增强生成(RAG)3.1 RAG是什么3.2 生成式AI应用开发3.3 RAG的整体流程3.4 RAG技术3.4.1 简单RAG(Simple RAG)3.4.2 校正RAG(Corrective RAG)3.4…

鸿蒙产业学院正式揭牌!软通动力与深信息签署校企合作框架协议

12月27日&#xff0c;深圳信息职业技术学院&#xff08;简称“深信息”&#xff09;与软通动力信息技术&#xff08;集团&#xff09;股份有限公司&#xff08;简称“软通动力”&#xff09;正式签署校企合作框架协议&#xff0c;并共同揭牌成立鸿蒙产业学院。深信息校长王晖&a…

python轻量级框架-flask

简述 Flask 是 Python 生态圈中一个基于 Python 的Web 框架。其轻量、模块化和易于扩展的特点导致其被广泛使用&#xff0c;适合快速开发 Web 应用以及构建小型到中型项目。它提供了开发 Web 应用最基础的工具和组件。之所以称为微框架&#xff0c;是因为它与一些大型 Web 框架…

2024年河北省职业院校技能大赛 “信息技术应用创新赛项”(高职组)样题解法

​有问题请留言或主页私信咨询 2024年河北省职业院校技能大赛 “信息技术应用创新赛项”&#xff08;高职组&#xff09;样题 一、初始化环境 1.账号及默认密码如表1所示。 表1 账号及密码规划表 账 号密 码root&#xff08;服务端&#xff09;kylin2024!desk&#xff08…

gozero获取数据库内容报错解决方案与实践

这个错误通常出现在 Go 语言的数据库查询中&#xff0c;表示你尝试将一个不支持的数据类型&#xff08;[]uint8&#xff0c;即字节切片&#xff09;存储到一个 Go 类型&#xff08;*time.Time&#xff09;中。具体来说&#xff0c;create_time 列的类型可能是 DATETIME 或 TIME…

【学习笔记15】如何在非root服务器中,安装属于自己的redis

一、下载安装包 官网下载黑马程序员给的安装包&#xff08;redis-6.2.6&#xff09; 二、将安装包上传至服务器 我将安装包上传在我的文件夹/home/XXX&#xff0c;指定路径中/src/local/redis/&#xff0c;绝对路径为/home/XXX/src/local/redis/解压安装包 XXXomega:~$ cd …

PotPlayer 配置安装

文章目录 一、下载1、官网链接2、微软商店 Microsoft Store 二、安装1、双击安装包2、选择字体3、安装向导下一步4、接收许可协议5、选择组件及关联6、选择安装位置7、硬解选项 三、设置1、关闭自动更新2、左键单双击设置3、视频下自动隐藏3.1、效果对比 4、播放信息显示设置4.…

【PCIe 总线及设备入门学习专栏 2 -- PCIe 的 LTSSM 和 Enumeration】

文章目录 OverviewLTSSM StatesDetect StatesDETECT_QUIETDETECT_ACTDETECT_WAITPolling StatesPOLL_ACTIVEPOLL_CONFIGPOLL_COMPLIANCEConfiguration StatesCONFIG_LINKWD_STARTCONFIG_LINKWD_ACCEPTCONFIG_LANENUM_WAITCONFIG_LANENUM_ACCEPTCONFIG_COMPLETECONFIG_IDLERecov…

STM32 FreeROTS Tickless低功耗模式

低功耗模式简介 FreeRTOS 的 Tickless 模式是一种特殊的运行模式&#xff0c;用于最小化系统的时钟中断频率&#xff0c;以降低功耗。在 Tickless 模式下&#xff0c;系统只在有需要时才会启动时钟中断&#xff0c;而在无任务要运行时则完全进入休眠状态&#xff0c;从而降低功…

【机器学习实战中阶】书籍推荐系统

图书推荐系统机器学习项目 通过这个机器学习项目&#xff0c;我们将构建一个图书推荐系统。对于这个项目&#xff0c;我们将使用 K 最近邻&#xff08;K-Nearest Neighbor, KNN&#xff09;算法。 让我们开始构建这个系统。 数据集说明 关于数据集 背景 在过去的几十年中…

嵌入式知识点总结 ARM体系与架构 专题提升(一)-硬件基础

嵌入式知识点总结 ARM体系与架构 专题提升(一)-硬件基础 目录 1.NAND FLASH 和NOR FLASH异同 ? 2.CPU,MPU,MCU,SOC,SOPC联系与差别? 3.什么是交叉编译&#xff1f; 4.为什么要交叉编译&#xff1f; 5.描述一下嵌入式基于ROM的运行方式和基于RAM的运行方式有什么区别? 1…

【数据分享】1929-2024年全球站点的逐月平均气温数据(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff0c;其中又以气温指标最为常用&#xff01;说到气温数据&#xff0c;最详细的气温数据是具体到气象监测站点的气温数据&#xff01;本次我们为大家带来的就是具体到气象监…

Kotlin Bytedeco OpenCV 图像图像54 透视变换 图像矫正

Kotlin Bytedeco OpenCV 图像图像54 透视变换 图像矫正 1 添加依赖2 测试代码3 测试结果 在OpenCV中&#xff0c;仿射变换&#xff08;Affine Transformation&#xff09;和透视变换&#xff08;Perspective Transformation&#xff09;是两种常用的图像几何变换方法。 变换方…

电梯系统的UML文档07

从这个类中得到的类图&#xff0c;构划出了软件的大部分设计。 系统结构视图提供软件和整个系统结构最复杂的也是最优雅的描述。和通常的软件系统相比&#xff0c;在分布式嵌入系统中了解系统组件如何协同工作是非常重要的。毕竟&#xff0c;每个类图仅仅是一个系统的静态设计…

文本摘要研究:从统计方法到大型语言模型

论文地址&#xff1a;https://arxiv.org/pdf/2406.11289 &#x1f4d6; 文本摘要研究&#xff1a;从统计方法到大型语言模型 近年来&#xff0c;文本摘要研究经历了多次重大变革&#xff0c;从深度神经网络的出现到预训练语言模型&#xff08;PLMs&#xff09;&#xff0c;再到…

MYSQL 5.7数据库,关于1067报错 invalid default value for,解决方法!

???作者&#xff1a; 米罗学长 ???个人简介&#xff1a;混迹java圈十余年&#xff0c;精通Java、小程序、数据库等。 ???各类成品java毕设 。javaweb&#xff0c;ssm&#xff0c;springboot&#xff0c;mysql等项目&#xff0c;源码丰富&#xff0c;欢迎咨询。 ???…

C ++ 也可以搭建Web?高性能的 C++ Web 开发框架 CPPCMS + MySQL 实现快速入门案例

什么是CPPCMS&#xff1f; CppCMS 是一个高性能的 C Web 开发框架&#xff0c;专为构建快速、动态的网页应用而设计&#xff0c;特别适合高并发和低延迟的场景。其设计理念类似于 Python 的 Django 或 Ruby on Rails&#xff0c;但针对 C 提供了更细粒度的控制和更高效的性能。…

一文大白话讲清楚webpack基本使用——2——css相关loader的配置和使用

一文大白话讲清楚webpack基本使用——2——css相关loader的配置和使用 1. 建议按文章顺序从头看是看 第一篇&#xff1a;一文大白话讲清楚啥是个webpack第二篇&#xff1a;一文大白话讲清楚webpack基本使用——1——完成webpack的初步构建然后看本篇&#xff0c;Loader的配置…