WPF开发-MVVM Toolkit框架的使用

前言

官方文档

https://docs.microsoft.com/zh-cn/dotnet/communitytoolkit/mvvm/

安装

在解决方案资源管理器中,右键单击项目,然后选择“管理NuGet包”。 搜索 Microsoft.Toolkit.Mvvm 并安装它。

1
Install-Package Microsoft.Toolkit.Mvvm -Version 7.1.2

添加 using 指令以使用新 API:

1
using Microsoft.Toolkit.Mvvm;

这个包主要提供了如下的

可观察对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class UserVM : ObservableObject
{
private string name;

public string Name
{
get => name;
set => SetProperty(ref name, value);
}

private int age;

public int Age
{
get => age;
set => SetProperty(ref age, value);
}
}

页面的类中添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public partial class MainWindow : Window
{
private UserVM userVM = new UserVM();

public MainWindow()
{
InitializeComponent();
DataContext = userVM;
Task.Run(() =>
{
while (true)
{
userVM.Age += 1;
Thread.Sleep(1000);
}
});
}
}

页面中

1
2
3
4
5
<Grid>
<StackPanel>
<TextBlock FontSize="30" Text="{Binding Age}" />
</StackPanel>
</Grid>

我们就可以看到数字就会一直递增了。

命令

页面中我们添加命令

1
2
3
4
5
6
<StackPanel Height="40" Orientation="Horizontal">
<TextBlock FontSize="30" Text="{Binding Name}" />
<TextBlock FontSize="30" Text="{Binding Age}" />

<Button Command="{Binding IncrementAgeCommand}" Content="年龄递增" />
</StackPanel>

对应的ViewModel中添加命令及响应的事件

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
public class UserVM : ObservableObject
{
private string name;

public string Name
{
get => name;
set => SetProperty(ref name, value);
}

private int age;

public int Age
{
get => age;
set => SetProperty(ref age, value);
}

public ICommand IncrementAgeCommand { get; }

public UserVM()
{
IncrementAgeCommand = new RelayCommand(IncrementAge);
}

private void IncrementAge() => Age++;
}

这样只要我们点击按钮,年龄就会递增1。

消息机制

注册与发送

添加传递消息的类

1
2
3
4
5
6
7
8
9
10
11
12
public class ZMessage
{
public int Code { get; set; }

public string Message { get; set; }

public ZMessage(int code, string msg)
{
Code = code;
Message = msg;
}
}

消息接收与发送

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public MainWindow()
{
InitializeComponent();
initMessage();
}

private void initMessage()
{
WeakReferenceMessenger.Default.Register<ZMessage>(
this,
(r, m) =>
{
Console.WriteLine("接收到信息:" + m.Message);
}
);

WeakReferenceMessenger.Default.Send(new ZMessage(100, "Hello"));
}

可接收消息的类

当然我们也可以让我们的ViewModel接收消息

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
public class UserVM : ObservableRecipient, IRecipient<ZMessage>
{
private string name;

public string Name
{
get => name;
set => SetProperty(ref name, value);
}

private int age;

public int Age
{
get => age;
set => SetProperty(ref age, value);
}

public UserVM()
{
IsActive = true;
}

public void Receive(ZMessage message)
{
Name = message.Message;
Age = message.Code;
}
}

这里一定要注意

  • 要继承ObservableRecipient类,实现IRecipient<>接口。

  • 只有设置IsActive = true;,才能接收消息。

我们还是在页面的类中发送消息

1
WeakReferenceMessenger.Default.Send(new ZMessage(18, "XiaoMing"));

页面也稍做修改

1
2
3
4
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="30" Text="{Binding Name}" />
<TextBlock FontSize="30" Text="{Binding Age}" />
</StackPanel>

我们会发现页面上已经变更为我们发送消息的数据了。

控制反转(IOC)

添加依赖库Microsoft.Extensions.DependencyInjection

1
Install-Package Microsoft.Extensions.DependencyInjection -Version 6.0.0

创建我们要自动注入的类

加入如下是我们用户相关的服务

1
2
3
4
public interface IUserService
{
string getUserName();
}

1
2
3
4
5
6
7
public class UserService : IUserService
{
public string getUserName()
{
return "XiaoMing";
}
}

添加注入的控制

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
public partial class App : Application
{
public App()
{
Services = ConfigureServices();

this.InitializeComponent();
}

public new static App Current => (App)Application.Current;

public IServiceProvider Services { get; }

private static IServiceProvider ConfigureServices()
{
var services = new ServiceCollection();

services.AddSingleton<IUserService, UserService>();

// ViewModels
services.AddTransient<UserVM>();

return services.BuildServiceProvider();
}
}

其中

  • AddSingleton 单一实例服务
  • AddScoped 范围内的服务
  • AddTransient 暂时性服务

权重:

AddSingletonAddTransientAddScoped

生命周期:

  • AddSingleton

    项目启动-项目关闭 相当于静态类 只会有一个

    每一次获取的对象都是同一个

  • AddScoped

    请求开始-请求结束 在这次请求中获取的对象都是同一个

    请求时创建

  • AddTransient

    请求获取-(GC回收-主动释放)

    获取时创建 每一次获取的对象都不是同一个

注意:

由于AddScoped对象是在请求的时候创建的

所以不能在AddSingleton对象中使用

甚至也不能在AddTransient对象中使用

使用

1
2
private UserVM userVM = (UserVM)App.Current.Services.GetService(typeof(UserVM));
private IUserService userService = (IUserService)App.Current.Services.GetService(typeof(IUserService));

这样是不是感觉还麻烦了

但是如果我们的ViewModel是这样的

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
public class UserVM : ObservableObject
{
private string name;

public string Name
{
get => name;
set => SetProperty(ref name, value);
}

private int age;

public int Age
{
get => age;
set => SetProperty(ref age, value);
}

public ICommand IncrementAgeCommand { get; }

public IUserService userService { get; }

public UserVM(IUserService _userService)
{
userService = _userService;
IncrementAgeCommand = new RelayCommand(IncrementAge);
}

private void IncrementAge() => Age++;
}

这里的IUserService的实例并没有传入但是就可以用了,因为IOC框架已经自动注入了。