目录
1. 简介
包 CommunityToolkit.Mvvm
(名为 MVVM 工具包) 是一个现代、快速和模块化的 MVVM 库。 它是 Windows 社区工具包的一部分。
MVVM 工具包由 Microsoft 维护和发布,也是 .NET Foundation 的一部分。
MVVM 工具包还具有 .NET 6 目标,用于在 .NET 6 上运行时启用更多内部优化。
2. Nuget安装
3. 开发环境
VS2022
WPF应用程序
.NET6.0
4. 属性通知
添加引用 using CommunityToolkit.Mvvm.ComponentModel;
//viewModel继承ObservableObject
public class ViewAViewModel:ObservableObject
{
private string _name;
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
}
5. 命令
添加引用 using CommunityToolkit.Mvvm.Input;
5.1 RelayCommand
public IRelayCommand SendCommand { get; }
SendCommand=new RelayCommand(Send);
private void Send()
{
}
5.2 AsyncRelayCommand
支持异步操作
public IAsyncRelayCommand LoadCommand { get; }
LoadCommand = new AsyncRelayCommand(LoadAsync);
private async Task<string> LoadAsync()
{
await Task.Delay(TimeSpan.FromSeconds(5));
return "Load Success";
}
ExecutionTask属性可监视操作进度,可获取方法执行返回值等
IsRunning属性:检查操作完成时间
ViewA.xaml
<Window.Resources>
<con:TaskResultConverter x:Key="TaskResultConverter"/>
<con:BoolToVisibleConverter x:Key="BoolToVisibleConverter"/>
</Window.Resources>
<StackPanel Grid.Row="1" Orientation="Vertical">
<TextBlock Margin="5">
<Run Text="Task status:"/>
<Run Text="{Binding LoadCommand.ExecutionTask.Status, Mode=OneWay}"/>
<LineBreak/>
<Run Text="Result:"/>
<Run Text="{Binding LoadCommand.ExecutionTask, Converter={StaticResource TaskResultConverter}, Mode=OneWay}"/>
</TextBlock>
<!-- IsIndeterminate="True" 一直处在滚动状态-->
<ProgressBar IsIndeterminate="True" Visibility="{Binding LoadCommand.IsRunning,Converter={StaticResource BoolToVisibleConverter}, Mode=OneWay}" Width="200" Height="20" HorizontalAlignment="Left" Margin="5" />
<Button Content="AsyncCommand" Command="{Binding LoadCommand}" Width="200" Height="100" HorizontalAlignment="Left" Margin="5"/>
</StackPanel>
TaskResultConverter
public class TaskResultConverter : IValueConverter
{
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Task<string> val && val.IsCompleted)
{
return val.Result;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
BoolToVisibleConverter
public class BoolToVisibleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool val)
{
return val ? Visibility.Visible : Visibility.Collapsed;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
效果:
6. Messenger
接口 IMessenger 是可用于在不同对象之间交换消息的类型协定。
MVVM Toolkit提供现装实现:WeakReferenceMessenger在内部使用弱引用,为收件人提供自动内存管理。StrongReferenceMessenger使用强引用,并且要求开发人员在不再需要接收者时手动取消订阅收件人
消息可以是数据类型或者自定义实体
public class InfoMessage
{
public string Title { get; set; }
public string Message { get; set; }
public int Id { get; set; }
public DateTime Date { get; set; }
}
添加引用 using CommunityToolkit.Mvvm.Messaging;
注册消息
WeakReferenceMessenger.Default.Register<InfoMessage>(this, (r, m) =>
{
//do something
messageService?.ShowMessage(this, $"收到消息:{m.Message} Date:{m.Date}");
});
发送消息
WeakReferenceMessenger.Default.Send(new InfoMessage()
{
Date = DateTime.Now,
Message="AAA"
});
取消注册
WeakReferenceMessenger.Default.UnregisterAll(this);
7. Ioc
使用依赖项注入,它包括创建大量注入后端类的服务,这允许使用这些服务的代码不依赖于这些服务的实现详细信息,并且还可以轻松地交换这些服务的具体实现。
此模式还使平台特定的功能更易于后端代码使用,方法是通过服务进行抽象化,然后在需要时注入这些功能。
使用平台API:Ioc
添加引用 using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
public partial class App : Application
{
private Mutex mutex;
protected override void OnStartup(StartupEventArgs e)
{
//防止程序多开
mutex = new Mutex(true,nameof(MVVMDemo),out bool ret);
if(!ret)
{
MessageBox.Show("软件已经在运行中,请检查!!");
Environment.Exit(0);
}
InitialServices();
new ViewA().Show();
base.OnStartup(e);
}
private void InitialServices()
{
var services = new ServiceCollection();
//单一实例服务 每一次获取的对象都是同一个
services.AddSingleton<IMessageService, MessageBoxCustom>();
//暂时性服务 请求获取-(GC回收-主动释放) 获取时创建 每一次获取的对象都不是同一个
services.AddTransient<ViewAViewModel>();
var provider = services.BuildServiceProvider();
Ioc.Default.ConfigureServices(provider);
}
}
服务
public interface IMessageService
{
void ShowMessage(object owner, string message);
}
public class MessageBoxCustom : IMessageService
{
public void ShowMessage(object owner, string message)
{
MessageBox.Show(message);
}
}
调用:
private IMessageService messageService;
messageService=Ioc.Default.GetService<IMessageService>();
messageService?.ShowMessage(this, $" ");
构造函数注入
private IMessageService messageService;
//“构造函数注入”,这意味着 DI 服务提供商能够在创建所请求类型的实例时自动解析已注册服务之间的间接依赖关系。
public ViewAViewModel(IMessageService _messageService)
{
messageService = _messageService;
}
private void IOCTest()
{
//实际使用时并没有传入IMessageService 的实例,但可以使用,因为IOC框架自动注入
messageService?.ShowMessage(this, "IOC测试");
}
调用
public ViewA()
{
InitializeComponent();
DataContext = Ioc.Default.GetService<ViewAViewModel>();
}
8. 其他
8.1 global using
C#10新功能,新建文件GlobalUsing.cs
使用关键字 global 标识 using 指令,则 using 适用于整个项目
global using System;
global using System.Threading;
global using System.Threading.Tasks;
global using System.Windows.Data;
global using System.Globalization;
global using System.Windows;
global using CommunityToolkit.Mvvm.ComponentModel;
global using CommunityToolkit.Mvvm.DependencyInjection;
global using CommunityToolkit.Mvvm.Input;
global using CommunityToolkit.Mvvm.Messaging;
global using Microsoft.Extensions.DependencyInjection;
namespace MVVMDemo;
public class GlobalUsing
{
}
8.2 函数参数null检查
public void Show(string str)
{
//null检查
ArgumentNullException.ThrowIfNull(str);
}
异常的时候,就会出现:
System.ArgumentNullException: 'Value cannot be null. (Parameter 'str')'