一、为什么称MVVM被滥用

1、什么是MVVM?

MVVM是Model-View-ViewModel的简写。它本质上就是 MVC的改进版。MVVM模式有助于将应用程序的业务和表示逻辑与 用户界面 (UI) 清晰分离。 保持应用程序逻辑和UI之间的清晰分离有助于解决许多开发问题,并使应用程序更易于测试、维护和演变。 它还可以显著提高代码重用机会,并允许开发人员和 UI设计人员在开发应用各自的部分时更轻松地进行协作。

  MVVM可用于跨平台软件的代码架构设计。

2、如何被滥用的

  现在一说WPF就需要会MVVM,这股风起源于微软对WPF的宣传。MVVM固然有优势,但是微软描述了MVVM的使用场景。而大多数作者在描述MVVM时,不会去强调MVVM的使用场景。时间一长‘不会MVVM就不算会WPF’就真的变成了写WPF就得用MVVM,而不是MVVM很重要了。对此我希望大家可以正确理解MVVM不要滥用。

应用程序更易于测试、维护和演变。但是有以下缺点:

    MVVM本身会增加代码量,业务代码不复杂的小界面不适合使用,会增加编码时间和阅读代码的困难度。

    ViewModel分割了model与View间的直接关系,让操作View使用的代码变多;降低编程的快感;

    对于只有一两位开发人员的小型应用程序来说,这种严格分离带来的好处可能无法抵消编码所浪费的时间。原有的事件机制更适合这种程序;

    对于复杂的View,我们在不使用MVVM时,建立一个有嵌套结构的Model就已经感觉到困难,再加一个MVVM的ViewModel要考虑时事情就变多了。可能需要重构ViewModel才能解决。

3、什么时候该用?什么时候不该用?

  (1)该用:

    ① 对View修改频繁,则用MVVM(无需触及代码即可重新设计应用 UI,前提是视图完全在 XAML 中实现);

应用程序的业务开发人员独立时,可以用MVVM模式分离View与Model;但是要消耗一些时间做好沟通,不要影响上线周期;

    ③ View 与 ViewModel 的分离还使得 ViewModel 更有利于单元测试和重用;需要对View进行独立测试或者排除View进行单元测试时,则选择MVVM;

    ④ 大型项目;

  (2)不该用:

    ① 对View后续控件改动不大;

应用程序业务不复杂的小项目;

  (3)都可,根据软件实际情况和代码开发者习惯进行考虑:

    ① 中等项目,后续会改动,界面改动不频繁。

4、使用MVVM后,代码如何写

  记住下面的原则即可:

  1、Model对业务负责,ViewModel对View负责;ViewModel中使用Model中的数据写View相关的逻辑,业务代码写在其他类(如BLL、Service)中,也可直接写在Model中;

  2、Model不了解平台或 ViewModel,Viewmodel可以直接访问Model上的属性和方法,

  3、WPF中的窗体展示可使用如下代码(传参示例)

public MainWindow(MainViewModel mainViewModel)
        {
            InitializeComponent();

            if (mainViewModel != null)
            {
                DataContext = mainViewModel;
            }
        }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

二、原生MVVM案例

  项目地址: https://gitee.com/qq28069933146_admin/wpf_mvvm_simple

1、MVVM知识点

WPF-理解与使用MVVM,请勿滥用_WPF

  想要创建一个完整的MVVM,需要用到以下类型或修饰词:

  • Window.DataContext:View Window强绑定ViewModel;
  • Binding:View绑定ViewModel中的变量、事件;
  • INotifyPropertyChanged:用于ViewModel通知View刷新;ViewModel继承该类,并实现PropertyChanged、OnPropertyChanged;
  • ICommand:用于VIew通知ViewModel响应控件事件;创建ICommand的实现类RelayCommand,并实现CanExecuteChanged,CanExecute,Execute;
2、创建Model
namespace WPF_MVVM_Simple.Model
{
    /// <summary>
    /// 用户信息
    /// </summary>
    public class UserModel
    {
        /// <summary>
        /// 主键
        /// </summary>
        public string ID { get; set; } = string.Empty;

        /// <summary>
        /// 用户名
        /// </summary>
        public string Name { get; set; } = string.Empty;

        /// <summary>
        /// 用户邮箱
        /// </summary>
        public string Email { get; set; } = string.Empty;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
3、创建View

  注意已下代码:

  • Window.DataContext:View Window强绑定ViewModel;
  • Binding:View绑定ViewModel中的变量、事件;
<Window x:Class="WPF_MVVM_Simple.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPF_MVVM_Simple"
        xmlns:vModel="clr-namespace:WPF_MVVM_Simple.ViewModel"
        mc:Ignorable="d"
        Title="MVVM原生示例" Height="450" Width="800">
    <Window.DataContext>
        <vModel:MainViewModel />
    </Window.DataContext>
    <Grid>
        <Label Content="名字:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
        <TextBox Text="{Binding Name, Mode=TwoWay}" HorizontalAlignment="Left" Margin="56,14,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="139"/>
        <Label Content="邮箱:" HorizontalAlignment="Left" Margin="10,40,0,0" VerticalAlignment="Top"/>
        <TextBox Text="{Binding Email }" HorizontalAlignment="Left" Margin="56,44,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="139"/>

        <!--Click="Button_Click"-->
        <Button Content="获取作者信息" Command="{Binding ButtonCommand}" HorizontalAlignment="Left" Margin="213,13,0,0" VerticalAlignment="Top" RenderTransformOrigin="0,-0.272" Width="90" />
        <!--Click="Button1_Click"-->
        <Button Content="和作者打招呼" Command="{Binding Button1Command}" HorizontalAlignment="Left" Margin="213,44,0,0" VerticalAlignment="Top" RenderTransformOrigin="0,-0.272" Width="90" />

        <Label Content="{Binding Log }" Margin="28,100,28,13" FontSize="72" Foreground="#FF00EDE8" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Window>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WPF_MVVM_Simple.Model;
using WPF_MVVM_Simple.ViewModel;

namespace WPF_MVVM_Simple
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        //外部传值
        public MainWindow(MainViewModel mainViewModel)
        {
            InitializeComponent();

            if (mainViewModel != null)
            {
                this.DataContext = mainViewModel;
            }
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
4、创建ViewModel
  • ViewModelBase为INotifyPropertyChanged的实现类;
  • RelayCommand为ICommand的实现类;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using WPF_MVVM_Simple.Commands;
using WPF_MVVM_Simple.Model;

namespace WPF_MVVM_Simple.ViewModel
{
    /// <summary>
    /// MainWindow的ViewModel类
    /// 集合 请使用 ObservableCollection<MainViewModel>
    /// </summary>
    public class MainViewModel : ViewModelBase
    {
        #region 控件 Binding
        private string _name = string.Empty;
        /// <summary>
        /// 名字
        /// </summary>
        public string Name
        {
            get => _name;
            set
            {
                _name = value;
                OnPropertyChanged("Name");  // 通知UI
            }
        }

        private string _email = string.Empty;
        /// <summary>
        /// 邮箱
        /// </summary>
        public string Email
        {
            get => _email;
            set
            {
                _email = value;
                OnPropertyChanged("Email");  // 通知UI
            }
        }

        private string _log = string.Empty;
        /// <summary>
        /// 打招呼的日志
        /// </summary>
        public string Log
        {
            get => _log;
            set
            {
                _log = value;
                OnPropertyChanged("Log");  // 通知UI
            }
        }
        #endregion 控件 Binding

        #region 控件事件
        /// <summary>
        /// 获取作者信息Command
        /// 数据流向:Model-> ViewModel-> View
        /// </summary>
        public ICommand ButtonCommand => new RelayCommand(
                    excute =>
                    {
                        // Model ->ViewModel
                        UserModel userModel = new UserModel()
                        {
                            ID = Guid.NewGuid().ToString("N"),
                            Name = "Bili执笔小白",
                            Email = "2806933146@qq.com"
                        };

                        #region 清空字符串(可省略)
                        Name = string.Empty;
                        Email = string.Empty;
                        Log = string.Empty;
                        #endregion 清空字符串(可省略)

                        Name = userModel.Name;
                        Email = userModel.Email;
                    },
                    canExcute => { return true; }
                );

        /// <summary>
        /// 和作者打招呼Command
        /// 数据流向:ViewModel-> View
        /// </summary>
        public ICommand Button1Command => new RelayCommand(
                    excute =>
                    {
                        Log = "你好!" + Name;
                    },
                    canExcute => { return true; }
                );
        #endregion 控件事件
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
5、实现INotifyPropertyChanged

  INotifyPropertyChanged:用于ViewModel通知View刷新;ViewModel继承该类,并实现PropertyChanged、OnPropertyChanged;

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WPF_MVVM_Simple.ViewModel
{
    /// <summary>
    /// ViewModel基类,主要为实现INotifyPropertyChanged接口
    /// </summary>
    public class ViewModelBase : INotifyPropertyChanged
    {
        /// <summary>
        /// MVVM 绑定事件
        /// </summary>
        public event PropertyChangedEventHandler? PropertyChanged;

        /// <summary>
        /// 数据变更时通知UI
        /// </summary>
        /// <param name="propName">绑定的值</param>
        protected virtual void OnPropertyChanged(string propName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
6、实现ICommand

  ICommand:用于VIew通知ViewModel响应控件事件;创建ICommand的实现类RelayCommand,并实现CanExecuteChanged,CanExecute,Execute;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace WPF_MVVM_Simple.Commands
{
    /// <summary>
    /// 用ICommand解耦‘用户界面’与‘事件’,即控件事件不写在页面的默认.cs代码中
    /// 这是实现MVVM(Model-View-ViewModel)设计模式的关键部分
    /// </summary>
    public class RelayCommand : ICommand
    {
        #region 变量
        /// <summary>
        /// 执行操作
        /// </summary>
        private Action<object?> _Excute;
        /// <summary>
        /// 如果可以执行Execute方法,则返回true;否则返回false
        /// </summary>
        private Func<object?, bool> _CanExcute;

        /// <summary>
        /// 当CanExecute的返回值可能发生更改时,会触发该事件
        /// </summary>
        public event EventHandler? CanExecuteChanged;
        #endregion 变量

        /// <summary>
        /// 如果可以执行Execute方法,则返回true;否则返回false
        /// </summary>
        /// <param name="parameter"></param>
        /// <returns></returns>
        public bool CanExecute(object? parameter)
        {
            return _CanExcute == null ? true : _CanExcute(parameter);
        }

        /// <summary>
        /// 执行操作
        /// </summary>
        /// <param name="parameter"></param>
        public void Execute(object? parameter)
        {
            if (_Excute != null)
                _Excute(parameter);
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="ExcuteMethod"></param>
        /// <param name="CanExcuteMethod"></param>
        public RelayCommand(Action<object?> ExcuteMethod, Func<object?, bool> CanExcuteMethod)
        {
            _Excute = ExcuteMethod;
            _CanExcute = CanExcuteMethod;
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
7、效果

WPF-理解与使用MVVM,请勿滥用_MVVM_02

WPF-理解与使用MVVM,请勿滥用_WPF_03

8、补充:

 (1)若ViewModel中有List<>或Array[]类型的变量,请使用ObservableCollection<>代替;ObservableCollection知识见:WPF-双向绑定通知机制之ObservableCollection;

三、简化MVVM代码量(CommunityToolkit.MVVM)

  项目地址: https://gitee.com/qq28069933146_admin/wpf_mvvm_simple

  在一、中我们完成了原生MVVM的开发,能够发现一个问题,ViewModel中我们添加一个成员对象就需要添加下面一段代码

private string _name = string.Empty;
        /// <summary>
        /// 名字
        /// </summary>
        public string Name
        {
            get => _name;
            set
            {
                _name = value;
                OnPropertyChanged("Name");  // 通知UI
            }
        }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

  那我们能不能像平时写model一样,只添加public string Name{get;set;} = string.Empty;呢,大概是肯定的。我们只需要引入CommunityToolkit.MVVM包即可;当然代码也不可能是public string Name{get;set;} = string.Empty;,而是[ObservableProperty]private string _name = string.Empty;,类名也需要继承ObservableObject并添加partial修饰词,完整代码如下:

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Xml.Linq;
using WPF_CommunityToolkitMVVM_Simple.Model;

namespace WPF_CommunityToolkitMVVM_Simple.ViewModel
{
    /// <summary>
    /// MainWindow的ViewModel类
    /// 集合 请使用 ObservableCollection<MainViewModel>
    /// </summary>
    public partial class MainViewModel : ObservableObject
    {
        #region 控件 Binding
        /// <summary>
        /// 名字
        /// </summary>
        [ObservableProperty]
        private string _name = string.Empty;

        /// <summary>
        /// 邮箱
        /// </summary>
        [ObservableProperty]
        private string _email = string.Empty;

        /// <summary>
        /// 打招呼的日志
        /// </summary>
        [ObservableProperty]
        private string _log = string.Empty;
        #endregion 控件 Binding

        #region 控件事件(可省略ButtonCommand变量直接写ButtonFunCommand;但为了好找到ButtonCommand,本文章不推荐省略;)
        /// <summary>
        /// 获取作者信息Command
        /// 数据流向:Model-> ViewModel-> View
        /// </summary>
        [RelayCommand]
        //public void ButtonFun(bool bool1)
        public void ButtonFun()
        {
            // Model ->ViewModel
            UserModel userModel = new UserModel()
            {
                ID = Guid.NewGuid().ToString("N"),
                Name = "Bili执笔小白",
                Email = "2806933146@qq.com"
            };

            #region 清空字符串(可省略)
            Name = string.Empty;
            Email = string.Empty;
            Log = string.Empty;
            #endregion 清空字符串(可省略)

            Name = userModel.Name;
            Email = userModel.Email;
        }

        //private RelayCommand<User>? buttonCommand;
        //public IRelayCommand<User> ButtonCommand => buttonCommand ??= new RelayCommand<bool>(ButtonFun);
        private RelayCommand? buttonCommand;
        public IRelayCommand ButtonCommand => buttonCommand ??= new RelayCommand(ButtonFun);


        /// <summary>
        /// 和作者打招呼Command - 异步
        /// 数据流向:ViewModel-> View
        /// </summary>
        [RelayCommand]
        public async Task Button1Fun()
        {
            await Task.Run(() =>
            {
                 Log = "你好!" + Name;
            });
        }

        private AsyncRelayCommand? button1Command;
        public IRelayCommand Button1Command => button1Command ??= new AsyncRelayCommand(Button1Fun);
        #endregion 控件事件(可省略ButtonCommand变量直接写ButtonFunCommand;但为了好找到ButtonCommand,本文章不推荐省略;)
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
1、CommunityToolkit.MVVM可简化哪些代码
  • 可简化上面代码块中的代码;即ViewModel继承ObservableObject并添加partial修饰词,即可省略OnPropertyChanged
  • 省略OnPropertyChanged就意味着可删除ViewModelBase类;
  • ObservableObject自带RelayCommand的实现,可删除我们项目里的RelayCommand类(使用案例如上代码);
  • 可省略ButtonCommand变量直接写ButtonFunCommand;但为了好找到ButtonCommand,本文章不推荐省略;
2、解析RelayCommand类

(1)RelayCommand无参与有参

  无参

// 可省略ButtonCommand变量直接写ButtonFunCommand;但为了好找到ButtonCommand,本文章不推荐省略;
        [RelayCommand]
        //public void ButtonFun(bool bool1)
        public void ButtonFun()
        {
        }
        private RelayCommand? buttonCommand;
        public IRelayCommand ButtonCommand => buttonCommand ??= new RelayCommand(ButtonFun);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

  有参

// 可省略ButtonCommand变量直接写ButtonFunCommand;但为了好找到ButtonCommand,本文章不推荐省略;
        [RelayCommand]
        public void ButtonFun(User user1)
        {
        }

        private RelayCommand<User>? buttonCommand;
        public IRelayCommand<User> ButtonCommand => buttonCommand ??= new RelayCommand<User>(ButtonFun);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

(2)AsyncRelayCommand异步无参与有参

  无参

// 可省略ButtonCommand变量直接写ButtonFunCommand;但为了好找到ButtonCommand,本文章不推荐省略;        
        [RelayCommand]
        public async Task Button1Fun()
        {
            // 示例代码1
            await Task.Run(() =>
            {
                ...
            });
            
            // 示例代码2
            await ...
        }

        private AsyncRelayCommand? button1Command;
        public IRelayCommand Button1Command => button1Command ??= new AsyncRelayCommand(Button1Fun);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

  有参

// 可省略ButtonCommand变量直接写ButtonFunCommand;但为了好找到ButtonCommand,本文章不推荐省略;
        [RelayCommand]
        public async Task Button1Fun(User user1)
        {
            // 示例代码1
            await Task.Run(() =>
            {
                ...
            });
            
            // 示例代码2
            await ...
        }

        private AsyncRelayCommand<User>? button1Command;
        public IRelayCommand<User> Button1Command => button1Command ??= new AsyncRelayCommand<User>(Button1Fun);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
3、IOCDI(CommunityToolkit.MVVM)

Light用于实现MVVM;CommunityToolkit.MVVM的IOCDI功能继承于MVVMLight。

所以 CommunityToolkit.MVVM的IOCDI可学可不学,微软推荐过的WPF IOCDI库有Microsoft.Extensions.DependencyInjection、Unity;

 

作者:꧁执笔小白꧂