.NET MAUI 基础知识总结(含路由跳转 + 弹窗详解)
PDA系统(登录、增删改查、路由跳转、下拉选择),
案例链接:https://download.csdn.net/download/ly1h1/92846901?spm=1001.2014.3001.5503
一、什么是 .NET MAUI?
.NET MAUI(.NET Multi-platform App UI) 是微软推出的跨平台移动 / 桌面 UI 框架,核心优势是「一套代码,多端运行」,无需为不同平台(Android、iOS、Windows、macOS)单独开发,极大降低跨平台开发成本。
核心特点:
- 开发语言:C# + XAML(界面描述语言),上手门槛低,适合.NET 开发者快速转型移动端
- 性能:接近原生应用,避免跨平台框架常见的性能损耗
- 集成能力:内置 MVVM、路由导航、网络请求、布局控件等全套开发能力,无需额外引入第三方库
- 适用场景:移动应用(手机端)、平板应用,也可扩展到桌面应用
二、MAUI 项目核心结构(实战对应版)
结合我们开发的智慧农业项目,标准 MAUI 项目结构如下(新手重点记这 5 个核心目录 / 文件):
plaintext
agricultureMobile(项目名)
├── Views // 页面目录(所有界面都在这里)
│ ├── LoginView.xaml // 登录页(项目入口)
│ ├── FarmView.xaml // 新增数据页
│ ├── ShedView.xaml // 数据列表页(改/删功能)
│ └── EditView.xaml // 编辑数据页
├── ViewModels // 业务逻辑目录(MVVM核心)
│ ├── LoginViewModel.cs // 登录逻辑
│ ├── FarmViewModel.cs // 新增逻辑(下拉选择)
│ ├── ShedViewModel.cs // 列表+修改+删除逻辑
│ └── EditViewModel.cs // 编辑逻辑
├── Models // 数据模型目录
│ └── DataItem.cs // 数据实体(A1Real、A2String、A3String)
├── AppShell.xaml // 路由导航配置(页面跳转核心)
└── MauiProgram.cs // 应用服务注册(程序启动入口)
关键说明:
- Views:只写界面(XAML),不写任何业务逻辑,保证「界面与逻辑分离」
- ViewModels:所有业务逻辑(网络请求、数据处理、按钮点击事件)都在这里
- AppShell.xaml:管理所有页面的路由,控制页面跳转规则,是 MAUI 导航的核心
三、XAML 基础(MAUI 界面开发语言)
XAML 是 MAUI 的界面描述语言,类似 HTML,语法简洁,专注于「描述界面布局和控件」,无需写代码就能完成界面开发。
1. 常用布局控件(实战高频)
布局控件用于控制页面元素的排列方式,我们项目中全部用到,新手重点掌握前 3 个:
表格
| 控件名称 | 作用 | 项目实战应用场景 |
|---|---|---|
<Grid /> |
网格布局(最常用、最稳定) | 实现列表滚动、按钮并排 |
<VerticalStackLayout /> |
垂直排列(从上到下) | 页面整体垂直布局、列表项内部布局 |
<HorizontalStackLayout /> |
水平排列(从左到右) | 按钮并排(修改 + 删除) |
<ScrollView /> |
滚动视图 | 新增页、登录页(避免内容溢出) |
<CollectionView /> |
列表控件(展示多条数据) | 大棚数据列表展示 |
实战示例(Grid 布局,解决列表不滚动问题):
xml
<!-- 根布局用Grid,实现列表正常滚动 -->
<Grid RowDefinitions="Auto,*">
<!-- 第1行:刷新按钮(自适应高度) -->
<Button Grid.Row="0" Text="刷新数据" Command="{Binding LoadCommand}" />
<!-- 第2行:列表(占满剩余所有空间,支持滚动) -->
<CollectionView Grid.Row="1" ItemsSource="{Binding Items}" />
</Grid>
2. 常用输入 / 展示控件(实战高频)
表格
| 控件名称 | 作用 | 项目实战应用场景 |
|---|---|---|
<Label /> |
文本展示 | 显示 "数值:XXX""参数 2:XXX" |
<Entry /> |
文本输入框 | 输入用户名、密码、A1Real、A2String |
<Picker /> |
下拉选择框 | A3String 下拉选择 A/B/C |
<Button /> |
按钮(触发事件) | 登录、提交、修改、删除、刷新 |
<Border /> |
圆角边框(美化界面) | 图片、表单美化 |
<Image /> |
图片展示 | 项目 Logo、大棚图片 |
实战示例(Picker 下拉选择框):
xml
<!-- 下拉选择框,绑定ViewModel中的数据源 -->
<Picker BackgroundColor="#F5F5F5"
Title="请选择参数3"
ItemsSource="{Binding A3Options}"
SelectedItem="{Binding A3String}"/>
四、MVVM 模式(MAUI 标准开发方式)
MVVM 是 MAUI 开发的核心模式,核心思想是「界面(View)与业务逻辑(ViewModel)分离」,便于维护和扩展,我们的项目全程采用这种模式。
1. MVVM 三要素(对应项目实战)
表格
| 要素 | 作用 | 项目对应文件 |
|---|---|---|
| View | 界面(XAML),只负责展示 | LoginView.xaml、ShedView.xaml 等 |
| ViewModel | 业务逻辑,处理数据、网络请求、事件 | LoginViewModel.cs、ShedViewModel.cs 等 |
| Model | 数据模型,存储数据结构 | DataItem.cs(A1Real、A2String 等) |
2. 核心接口:INotifyPropertyChanged(必写)
作用:实现 "数据变化 → 界面自动更新",比如输入框输入内容、下拉选择后,界面同步显示最新数据,是 MVVM 绑定的核心。
固定模板(所有 ViewModel 都要继承并实现,直接复制使用):
csharp
运行
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace agricultureMobile.ViewModels
{
public class BaseViewModel : INotifyPropertyChanged
{
// 事件:数据变化时触发
public event PropertyChangedEventHandler? PropertyChanged;
// 触发事件的方法(固定写法)
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
实战示例(ViewModel 中使用):
csharp
运行
// 继承BaseViewModel,无需重复写INotifyPropertyChanged
public class FarmViewModel : BaseViewModel
{
// 私有字段
private string _a2String = string.Empty;
// 公共属性(绑定到界面)
public string A2String
{
get => _a2String;
set
{
_a2String = value;
OnPropertyChanged(); // 数据变化时,通知界面更新
}
}
}
五、数据绑定 Binding(MAUI 灵魂)
数据绑定是连接 View 和 ViewModel 的桥梁,实现「界面与数据的自动关联」,无需手动操作界面控件,减少代码冗余。
1. 核心语法(实战常用)
xml
<!-- 界面控件绑定 ViewModel 中的属性 -->
<Entry Text="{Binding A1Real}" /> <!-- 输入框绑定 A1Real 属性 -->
<Picker ItemsSource="{Binding A3Options}" SelectedItem="{Binding A3String}" /> <!-- 下拉框绑定数据源和选中值 -->
<Button Command="{Binding LoginCommand}" /> <!-- 按钮绑定 Command 事件 -->
2. 绑定关键要求
-
View 的 BindingContext 必须设置为对应的 ViewModel(在 XAML 中设置): xml
<ContentPage.BindingContext> <vm:LoginViewModel /> <!-- 绑定LoginViewModel --> </ContentPage.BindingContext> -
ViewModel 中的属性必须有
get/set,且在set中调用OnPropertyChanged() -
绑定的属性名必须和 ViewModel 中的属性名完全一致(大小写敏感)
六、命令 Command(按钮点击事件,MVVM 模式)
MAUI 中,按钮点击不推荐用传统的点击事件(如 Click),而是用「Command 命令」,完全符合 MVVM 模式,实现 "界面与逻辑分离"。
1. 实战写法(固定模板)
第一步:ViewModel 中定义 Command
csharp
运行
using System.Windows.Input;
using Microsoft.Maui.Controls;
public class LoginViewModel : BaseViewModel
{
// 定义Command
public ICommand LoginCommand { get; }
// 构造函数中绑定Command对应的方法
public LoginViewModel()
{
// 绑定LoginAsync方法(按钮点击后执行)
LoginCommand = new Command(async () => await LoginAsync());
}
// Command对应的业务逻辑方法
private async Task LoginAsync()
{
// 登录逻辑(网络请求、参数校验等)
}
}
第二步:XAML 中绑定 Command
xml
<Button Text="登录"
Command="{Binding LoginCommand}"
BackgroundColor="#0FC97D"
TextColor="White"/>
2. 带参数的 Command(修改 / 删除功能必备)
比如列表中的 "修改""删除" 按钮,需要传递当前选中的数据,写法如下:
csharp
运行
// 带参数的Command(参数类型为DataItem)
public ICommand DeleteCommand { get; }
public ShedViewModel()
{
// 绑定带参数的DeleteItem方法
DeleteCommand = new Command<DataItem>(DeleteItem);
}
// 接收参数(当前选中的列表项)
private async void DeleteItem(DataItem item)
{
// 根据item.A1Real执行删除逻辑
}
XAML 绑定(传递当前列表项作为参数):
xml
<Button Text="删除"
Command="{Binding Source={x:Reference thisPage}, Path=BindingContext.DeleteCommand}"
CommandParameter="{Binding}" />
七、MAUI Shell 路由(页面跳转,核心重点)
Shell 是 MAUI 的路由导航系统,负责管理所有页面的跳转、传参、返回,我们项目中解决的 "路由报错、无法返回" 问题,都和 Shell 路由相关。
1. 路由注册(必须在 AppShell.xaml 中配置)
所有需要跳转的页面,都要在 AppShell.xaml 中注册路由,否则无法跳转。
实战示例(我们项目的路由配置):
xml
<Shell
x:Class="agricultureMobile.AppShell"
xmlns:v="clr-namespace:agricultureMobile.Views"
Shell.FlyoutBehavior="Disabled">
<!-- 1. 登录页(启动页,不放在TabBar中) -->
<ShellContent Route="LoginView" ContentTemplate="{DataTemplate v:LoginView}" />
<!-- 2. 底部Tab页(主页面) -->
<TabBar>
<ShellContent Title="农场2" ContentTemplate="{DataTemplate v:FarmView}" Icon="nc_icon.png" />
<ShellContent Title="大棚" ContentTemplate="{DataTemplate v:ShedView}" Icon="dp_icon.png" Route="ShedView" />
<ShellContent Title="我的" ContentTemplate="{DataTemplate v:MineView}" Icon="wd_icon.png" />
</TabBar>
<!-- 3. 编辑页(子页面,不放在TabBar中) -->
<ShellContent ContentTemplate="{DataTemplate v:EditView}" Route="EditView"/>
</Shell>
关键规则:
- 主页面(底部 Tab)放在
<TabBar>中 - 子页面(编辑页、弹窗页)放在
<TabBar>外部,避免无法返回 - 每个页面必须指定
Route="页面名"(如 Route="ShedView"),用于跳转时定位页面
2. 两种核心跳转方式(重点!含弹窗)
MAUI Shell 跳转分为「普通页面跳转」和「模态弹窗跳转」,我们项目中用的是普通跳转,弹窗跳转可按需扩展。
方式 1:普通页面跳转(非弹窗,最常用)
语法:///页面路由名(三个斜杠,绝对路由,避免报错)
csharp
运行
// 登录成功后,跳转到大棚列表页(普通跳转,非弹窗)
await Shell.Current.GoToAsync("///ShedView");
// 列表页跳转到编辑页(带参数传参)
await Shell.Current.GoToAsync($"///EditView?A1Real={item.A1Real}&A2String={item.A2String}");
特点:
- 页面压入导航栈,支持返回(用
..返回上一页) - 无弹窗效果,是正常的页面切换
- 适合:登录→主页、列表→编辑等场景
方式 2:模态弹窗跳转(弹窗效果)
语法:modal://页面路由名(加 modal://,弹窗形式打开)
csharp
运行
// 以弹窗形式打开编辑页
await Shell.Current.GoToAsync("modal://EditView");
特点:
- 从页面底部弹出,类似手机弹窗效果
- 弹窗期间,无法操作底层页面
- 关闭弹窗(返回):
await Shell.Current.GoToAsync(".."); - 适合:新增、编辑等需要临时打开的页面
3. 路由传参与接收(修改功能必备)
第一步:跳转时传参(列表→编辑页)
csharp
运行
// 传递A1Real、A2String、A3String三个参数
await Shell.Current.GoToAsync($"///EditView?A1Real={item.A1Real}&A2String={item.A2String}&A3String={item.A3String}");
第二步:编辑页接收参数(ViewModel 中)
用 [QueryProperty] 特性接收参数,自动绑定到对应的属性:
csharp
运行
using Microsoft.Maui.Controls;
[QueryProperty(nameof(A1Real), nameof(A1Real))] // 接收A1Real参数
[QueryProperty(nameof(A2String), nameof(A2String))] // 接收A2String参数
[QueryProperty(nameof(A3String), nameof(A3String))] // 接收A3String参数
public class EditViewModel : BaseViewModel
{
private double _a1Real;
private string _a2String = string.Empty;
private string _a3String = string.Empty;
// 接收的参数会自动赋值到这些属性
public double A1Real
{
get => _a1Real;
set { _a1Real = value; OnPropertyChanged(); }
}
public string A2String
{
get => _a2String;
set { _a2String = value; OnPropertyChanged(); }
}
public string A3String
{
get => _a3String;
set { _a3String = value; OnPropertyChanged(); }
}
}
4. 页面返回(解决 "无法返回" 问题)
表格
| 场景 | 返回写法 | 实战应用 |
|---|---|---|
| 普通跳转返回上一页 | await Shell.Current.GoToAsync(".."); |
编辑页返回列表页 |
| 强制返回主页面 | await Shell.Current.GoToAsync("///ShedView"); |
任意页面返回大棚列表页 |
| 弹窗关闭 | await Shell.Current.GoToAsync(".."); |
弹窗编辑页关闭返回列表页 |
八、MAUI 网络请求(HttpClient,实战必备)
我们项目中的登录、新增、修改、删除、列表加载,都用到了 HttpClient 进行网络请求,这是 MAUI 中最常用的网络请求方式。
1. 核心写法(固定模板)
第一步:初始化 HttpClient(ViewModel 中)
csharp
运行
using System.Net.Http;
public class LoginViewModel : BaseViewModel
{
// 初始化HttpClient(全局一个即可)
private readonly HttpClient _httpClient = new HttpClient();
// 后续所有网络请求都用这个_httpClient
}
第二步:不同请求方式(对应项目接口)
表格
| 接口类型 | 写法示例(实战对应) |
|---|---|
| POST(登录 / 新增) | 登录:await _httpClient.PostAsync("http://193.112.175.157:8001/login", content); |
| PUT(修改) | 修改:await _httpClient.PutAsync($"http://193.112.175.157:8001/update/{_originalA1Real}", content); |
| DELETE(删除) | 删除:await _httpClient.DeleteAsync($"http://193.112.175.157:8001/delete/{item.A1Real}"); |
| GET(列表加载) | 列表:var res = await _httpClient.GetStringAsync("http://193.112.175.157:8001/list"); |
第三步:请求参数构造(JSON 格式)
csharp
运行
using Newtonsoft.Json;
using System.Text;
// 1. 构造请求参数(和接口入参一致)
var requestObj = new
{
username = Username,
password = Password
};
// 2. 转换为JSON字符串
var json = JsonConvert.SerializeObject(requestObj);
// 3. 构造请求内容(指定编码和格式)
var content = new StringContent(json, Encoding.UTF8, "application/json");
九、MAUI 弹窗提示(用户交互必备)
用于显示提示信息(成功、失败、确认),我们项目中登录、新增、修改、删除都用到了,写法固定。
1. 常用弹窗类型
(1)提示弹窗(只有确定按钮)
csharp
运行
// 格式:await Shell.Current.CurrentPage.DisplayAlert("标题", "内容", "确定按钮文本");
await Shell.Current.CurrentPage.DisplayAlert("成功", "删除完成", "确定");
(2)确认弹窗(确定 + 取消按钮,用于删除、危险操作)
csharp
运行
// 格式:await Shell.Current.CurrentPage.DisplayAlert("标题", "内容", "确定按钮", "取消按钮");
bool confirm = await Shell.Current.CurrentPage.DisplayAlert("确认删除", $"确定要删除 {item.A1Real} 吗?", "确定", "取消");
if (confirm)
{
// 用户点击确定,执行删除逻辑
}
else
{
// 用户点击取消,取消操作
}
一、传统弹窗(.NET MAUI 通用写法)
1. 打开弹窗
csharp
运行
var editPage = new EditView();
await Navigation.PushModalAsync(editPage);
或
csharp
运行
await Shell.Current.Navigation.PushModalAsync(new EditView());
2. 关闭弹窗
csharp
运行
await Navigation.PopModalAsync();
十、MAUI 实战避坑指南(新手必看)
结合我们项目中遇到的问题,整理 10 个高频坑,避免新手走弯路:
- 列表(CollectionView)不滚动、显示不全?→ 不要放在 VerticalStackLayout 中,用 Grid 布局(RowDefinitions="Auto,*")
- 路由报错 "Relative routing not supported"?→ 跳转用绝对路由(/// 页面名),不要用相对路由
- 编辑页无法返回?→ 编辑页(EditView)不要放在 TabBar 中,放在 TabBar 外部
- 按钮提示 "FillAndExpand 已过时"?→ 用 Grid 替代 HorizontalStackLayout 实现按钮并排,避免用 FillAndExpand
- 数据绑定后,界面不更新?→ 忘记在 ViewModel 的属性 set 中调用 OnPropertyChanged ()
- 路由传参接收不到?→ 确保 QueryProperty 的属性名和传参名一致,且属性有 get/set
- 弹窗提示报错 "MainPage 为空"?→ 用 Shell.Current.CurrentPage.DisplayAlert (),不要用 Application.Current.MainPage
- 下拉选择框(Picker)无数据?→ 确保 ItemsSource 绑定的集合已初始化(如 ObservableCollection)
- 网络请求失败?→ 检查接口地址是否正确,参数格式是否为 JSON
- 页面跳转后,数据不刷新?→ 跳转后手动调用列表加载方法(如 LoadData ())
十一、MAUI 学习路线
结合我们的实战项目,新手可以按以下顺序学习,快速上手 MAUI:
- 基础:XAML 布局(Grid、StackLayout、CollectionView 等常用控件)
- 核心:MVVM 模式 + INotifyPropertyChanged + 数据绑定
- 进阶:Shell 路由(跳转、传参、返回、弹窗)
- 实战:网络请求(HttpClient + JSON 解析)
- 扩展:表单输入(Entry、Picker)、弹窗提示、列表增删改查
- 优化:界面美化、性能优化、避坑技巧