深入理解.NET MAUI Workshop中的MVVM与数据绑定

深入理解.NET MAUI Workshop中的MVVM与数据绑定

【免费下载链接】dotnet-maui-workshop A full day workshop (.NET MAUI Workshop in a Box) on how to build apps with .NET MAUI for iOS, Android, macOS, and Windows 【免费下载链接】dotnet-maui-workshop 项目地址: https://gitcode.com/gh_mirrors/do/dotnet-maui-workshop

本文是dotnet-maui-workshop项目第二部分的技术解析,将全面介绍如何在.NET MAUI中实现MVVM模式和数据绑定,并展示如何从网络数据源获取猴子信息。

MVVM模式基础

MVVM(Model-View-ViewModel)是一种设计模式,它将用户界面逻辑与业务逻辑分离,使代码更易于维护和测试。在.NET MAUI中,MVVM模式通过数据绑定实现视图与视图模型之间的通信。

INotifyPropertyChanged实现

INotifyPropertyChanged接口是MVVM框架中数据绑定的核心。当模型属性发生变化时,该接口会通知视图进行更新。

基础实现步骤:
  1. 创建BaseViewModel基类并实现INotifyPropertyChanged接口
  2. 添加PropertyChanged事件
  3. 创建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指定视图模型类型可以获得:

  1. 编译时绑定验证
  2. 更好的性能
  3. 开发时智能提示

总结

本文详细介绍了在.NET MAUI中实现MVVM模式的完整流程,包括:

  1. 基础属性变更通知实现
  2. 使用社区工具包简化代码
  3. 数据服务层设计
  4. 视图模型与命令处理
  5. 依赖注入配置
  6. 视图层数据绑定

这些技术组合在一起,可以构建出结构清晰、易于维护的跨平台应用。MVVM模式特别适合复杂界面的开发,它能有效分离关注点,提高代码的可测试性和可维护性。

【免费下载链接】dotnet-maui-workshop A full day workshop (.NET MAUI Workshop in a Box) on how to build apps with .NET MAUI for iOS, Android, macOS, and Windows 【免费下载链接】dotnet-maui-workshop 项目地址: https://gitcode.com/gh_mirrors/do/dotnet-maui-workshop

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值