深入理解.NET MAUI Workshop中的MVVM与数据绑定
本文是dotnet-maui-workshop项目第二部分的技术解析,将全面介绍如何在.NET MAUI中实现MVVM模式和数据绑定,并展示如何从网络数据源获取猴子信息。
MVVM模式基础
MVVM(Model-View-ViewModel)是一种设计模式,它将用户界面逻辑与业务逻辑分离,使代码更易于维护和测试。在.NET MAUI中,MVVM模式通过数据绑定实现视图与视图模型之间的通信。
INotifyPropertyChanged实现
INotifyPropertyChanged接口是MVVM框架中数据绑定的核心。当模型属性发生变化时,该接口会通知视图进行更新。
基础实现步骤:
- 创建
BaseViewModel基类并实现INotifyPropertyChanged接口 - 添加
PropertyChanged事件 - 创建
OnPropertyChanged方法触发属性变更通知
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string name = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
常用属性实现
在基类中通常会包含一些通用属性:
bool isBusy;
string title;
public bool IsBusy
{
get => isBusy;
set
{
if (isBusy == value) return;
isBusy = value;
OnPropertyChanged();
OnPropertyChanged(nameof(IsNotBusy));
}
}
public string Title
{
get => title;
set
{
if (title == value) return;
title = value;
OnPropertyChanged();
}
}
public bool IsNotBusy => !IsBusy;
使用.NET社区工具包简化MVVM
随着应用复杂度增加,手动实现MVVM会变得繁琐。.NET社区工具包提供了简化方案:
public partial class BaseViewModel : ObservableObject
{
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(IsNotBusy))]
bool isBusy;
[ObservableProperty]
string title;
public bool IsNotBusy => !IsBusy;
}
工具包通过源代码生成器自动生成属性变更通知代码,大大减少了样板代码量。
数据服务层实现
MonkeyService服务类
创建从网络获取数据的服务:
public class MonkeyService
{
HttpClient httpClient;
List<Monkey> monkeyList = new();
public MonkeyService()
{
this.httpClient = new HttpClient();
}
public async Task<List<Monkey>> GetMonkeys()
{
if (monkeyList?.Count > 0)
return monkeyList;
var response = await httpClient.GetAsync("https://www.montemagno.com/monkeys.json");
if (response.IsSuccessStatusCode)
{
monkeyList = await response.Content.ReadFromJsonAsync(MonkeyContext.Default.ListMonkey);
}
return monkeyList;
}
}
离线数据支持
为应对网络问题,可以添加本地数据支持:
using var stream = await FileSystem.OpenAppPackageFileAsync("monkeydata.json");
using var reader = new StreamReader(stream);
var contents = await reader.ReadToEndAsync();
monkeyList = JsonSerializer.Deserialize(contents, MonkeyContext.Default.ListMonkey);
视图模型实现
MonkeysViewModel核心逻辑
public partial class MonkeysViewModel : BaseViewModel
{
public ObservableCollection<Monkey> Monkeys { get; } = new();
MonkeyService monkeyService;
public MonkeysViewModel(MonkeyService monkeyService)
{
Title = "Monkey Finder";
this.monkeyService = monkeyService;
}
[RelayCommand]
async Task GetMonkeysAsync()
{
if (IsBusy) return;
try
{
IsBusy = true;
var monkeys = await monkeyService.GetMonkeys();
if(Monkeys.Count != 0)
Monkeys.Clear();
foreach(var monkey in monkeys)
Monkeys.Add(monkey);
}
catch (Exception ex)
{
Debug.WriteLine($"Unable to get monkeys: {ex.Message}");
await Shell.Current.DisplayAlert("Error!", ex.Message, "OK");
}
finally
{
IsBusy = false;
}
}
}
依赖注入配置
在MauiProgram.cs中注册服务:
builder.Services.AddSingleton<MonkeyService>();
builder.Services.AddSingleton<MonkeysViewModel>();
用户界面构建
MainPage.xaml数据绑定
<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MonkeyFinder.View.MainPage"
xmlns:model="clr-namespace:MonkeyFinder.Model"
xmlns:viewmodel="clr-namespace:MonkeyFinder.ViewModel"
x:DataType="viewmodel:MonkeysViewModel"
Title="{Binding Title}">
<Grid
ColumnDefinitions="*,*"
ColumnSpacing="5"
RowDefinitions="*,Auto"
RowSpacing="0">
<CollectionView
Grid.ColumnSpan="2"
ItemsSource="{Binding Monkeys}"
SelectionMode="None">
<!-- 列表项模板 -->
</CollectionView>
<Button
Grid.Row="1"
Grid.Column="0"
Text="Get Monkeys"
Command="{Binding GetMonkeysCommand}"/>
</Grid>
</ContentPage>
编译绑定优势
使用x:DataType指定视图模型类型可以获得:
- 编译时绑定验证
- 更好的性能
- 开发时智能提示
总结
本文详细介绍了在.NET MAUI中实现MVVM模式的完整流程,包括:
- 基础属性变更通知实现
- 使用社区工具包简化代码
- 数据服务层设计
- 视图模型与命令处理
- 依赖注入配置
- 视图层数据绑定
这些技术组合在一起,可以构建出结构清晰、易于维护的跨平台应用。MVVM模式特别适合复杂界面的开发,它能有效分离关注点,提高代码的可测试性和可维护性。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



