当前位置:首页 » 《随便一记》 » 正文

MAUI 中使用 DI 及 MVVM

8 人参与  2022年11月28日 14:42  分类 : 《随便一记》  评论

点击全文阅读


MAUI 中使用 DI 及 MVVM

为什么要使用 依赖注入 和 MVVM如何在 MAUI 中使用依赖注入如何使用 MVVM不使用框架或组件定义一个 BaseViewModelMainViewModel 的实现MainPage 中进行 Binding 使用组件优化前面的 ViewModel 代码 基项目的效果

为什么要使用 依赖注入 和 MVVM

MVVM 和 依赖注入 有助于开发出松耦合可维护以及可测试的应用程序。

如何在 MAUI 中使用依赖注入

依赖注入在MAUI中是原生支持的。
创建一个MAUI APP项目,根目录会有 MauiProgram.cs

public static MauiApp CreateMauiApp(){var builder = MauiApp.CreateBuilder();builder.UseMauiApp<App>().ConfigureFonts(fonts =>{fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");});// 注入页面builder.Services.AddTransient<MainPage>();return builder.Build();}
在 builder 中注入需要的页面或服务即可

如何使用 MVVM

不使用框架或组件

先说下不使用任何框架或组件是如何实现的。

定义一个 BaseViewModel

BaseViewModel 会被后来的 viewmodel 所继承,并且所有的公共属性、方法都将再次进行声明。
BaseViewModel 需要继承和实现 INotifyPropertyChanged 才能够实现 viewviewmodel 之间的通讯。

using System.ComponentModel;using System.Runtime.CompilerServices;namespace CrossPlatformTools.ViewModel{    public class BaseViewModel : INotifyPropertyChanged    {        private bool isBusy;        public bool IsBusy        {            get => isBusy;            set            {                if (isBusy == value)                    return;                isBusy = value;                OnPropertyChanged();                OnPropertyChanged(nameof(IsNoteBusy));            }        }        public bool IsNoteBusy => !IsBusy;        private string title;        public string Title        {            get => title;            set            {                if (title == value)                    return;                title = value;                OnPropertyChanged();            }        }        public event PropertyChangedEventHandler PropertyChanged;        public void OnPropertyChanged([CallerMemberName] string name = null) =>            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));    }}

MainViewModel 的实现

MainViewModel 继承 BaseViewModel 但是 MainViewModel 中独有的属性和方法还是需要的MainViewModel 中进行声明的。

namespace CrossPlatformTools.ViewModel{    public class MainViewModel : BaseViewModel    {        private int count = 0;        public int Count        {            get { return count; }            set            {                if (count == value)                    return;                count = value;                OnPropertyChanged();            }        }        public Command CountCommand { get; }        public MainViewModel()        {            Title = "首页";            CountCommand = new Command(OnCounter);        }        private void OnCounter()        {            Count++;        }    }}

在 BaseViewModel 声明的属性 MainViewModel 中就可以直接使用了。
Command 的声明相比于通知属性就简便很多。声明 Command 然后在构造函数中调用即可。

MainPage 中进行 Binding

在 xaml 中需要引入命名空间:
xmlns:viewmodel="clr-namespace:CrossPlatformTools.ViewModel"

只引入命名空间这时想要使用属性是无法提示的,还需要设置 DataType
x:DataType="viewmodel:MainViewModel"

<?xml version="1.0" encoding="utf-8" ?><ContentPage    x:Class="CrossPlatformTools.View.MainPage"    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"    xmlns:viewmodel="clr-namespace:CrossPlatformTools.ViewModel"    Title="{Binding Title}"    x:DataType="viewmodel:MainViewModel">    <Grid>        <VerticalStackLayout            Padding="30,0"            Spacing="25"            VerticalOptions="Center">            <Image                HeightRequest="200"                HorizontalOptions="Center"                SemanticProperties.Description="Cute dot net bot waving hi to you!"                Source="dotnet_bot.png" />            <Label                FontSize="18"                HorizontalOptions="Center"                SemanticProperties.Description="Welcome to dot net Multi platform App U I"                SemanticProperties.HeadingLevel="Level2"                Text="Welcome to .NET Multi-platform App UI" />            <Button                Command="{Binding CountCommand}"                HorizontalOptions="Center"                SemanticProperties.Hint="Counts the number of times you click"                Text="{Binding Count}" />        </VerticalStackLayout>    </Grid></ContentPage>

你以为这样就完了吗,当然不是,只在xaml中引入命名空间进行 CommandProperty 的Binding 是不行了,还要进行上下文绑定。

using CrossPlatformTools.ViewModel;namespace CrossPlatformTools.View;public partial class MainPage : ContentPage{    public MainPage(MainViewModel mainViewModel)    {        InitializeComponent();        BindingContext = mainViewModel;    }}

这里有的一不同点,一般来说 BindingContext 是这样做的 BindingContext = new MainViewModel() 但是我这里使用的是构造函数注入。
不能直接使用 需要在 MauiProgram.cs 中注入才能使用。

使用组件优化前面的 ViewModel 代码

原生的方式实现 MVVM 时, ViewModel 中的属性定义非常需要很多的代码,并且要手动实现 PropertyChanged 事件。

使用 CommunityToolkit.Mvvm 实现

官方描述:
此包包含一个.NET MVVM库,其中包含以下帮助程序:

ObservableObject:实现INotifyPropertyChanged接口的对象的基类。ObservableRecipient:支持IMessenger服务的可观察对象的基类。ObservableValidator:实现INotifyDataErrorInfo接口的对象的基类。RelayCommand:一个实现ICommand接口的简单委托命令。AsyncRelayCommand:支持异步操作和取消的委托命令。WeakReferenceMessenger:通过不同的松散耦合对象交换消息的消息传递系统。StrongReferenceMessenger:一个高性能的消息传递系统,以弱引用换取速度。Ioc:用于配置依赖注入服务容器的助手类。 CommunityToolkit.Mvvm 是基于 .NET Standard 实现,理论上适用于所有 .NET 平台应用。

需要引入 CommunityToolkit.Mvvm.ComponentModel 命名空间
使用 partial class 标识符,CommunityToolkit.Mvvm 内部实现使用的是源生成器,所有需要使用 partial 进行标识。
变量的声明必须使用驼峰式命名规则,才可以与生成的以 Pascal 命名规则的属性名不重复。

关于 源生成器 不明白的可以去看前面的文章 C# 源代码生成器 讲解了 源生成器的用法。

基类就变成了下面这样,少了很多的代码

using CommunityToolkit.Mvvm.ComponentModel;namespace CrossPlatformTools.ViewModel{    public partial class BaseViewModel : ObservableObject    {        [ObservableProperty]        [NotifyPropertyChangedFor(nameof(isNoteBusy))]        bool isBusy;        bool isNoteBusy => !isBusy;        [ObservableProperty]        string title;    }}
同样的 MainViewModel 代码也是要进行更改的,精简了很多。
using CommunityToolkit.Mvvm.ComponentModel;namespace CrossPlatformTools.ViewModel{    public partial class MainViewModel : BaseViewModel    {        [ObservableProperty]        private int count = 0;        public Command CountCommand { get; }        public MainViewModel()        {            Title = "首页";            CountCommand = new Command(OnCounter);        }        private void OnCounter()        {            Count++;        }    }}

基项目的效果

效果


点击全文阅读


本文链接:http://zhangshiyu.com/post/49180.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1