前言
MVVM工具包,以前名为 Microsoft.Toolkit.Mvvm 由 Microsoft 维护和发布,是 .NET Foundation 的一部分。
支持:.NET Standard 2.0、 .NET Standard 2.1 和 .NET 6(UI Framework 不可知,基本使用没有问题/编译特性用不了)
注:可以当做MvvmLight的替代品 大部分方法一样
安装:
安装:Nuget -> CommunityToolkit.MVVM
常规对象
ObservableObject:通知属性
第一种:基本通知属性
和MvvmLight一模一样
public partial class MainViewModel : ObservableObject
{
// 1、基本通知属性
private string _value;
public string Value
{
get { return _value; }
set
{
SetProperty(ref _value, value);
//_value = value;
//this.OnPropertyChanging();
}
}
}
第二种:直接通过实体返回 或者赋值
public partial class MainViewModel : ObservableObject
{
UserEntity userEntity = new UserEntity();
// 直接通过实体返回 或者赋值
public string UserName
{
get { return userEntity.userName; }
set
{
userEntity.userName = value;
this.OnPropertyChanging(nameof(UserName));
// 通过 SetProperty 给 Model 赋值
SetProperty<UserEntity, string>(userEntity.userName, value, userEntity, (entity, v) => { entity.userName = v; });
}
}
}
public class UserEntity
{
public string userName { get; set; }
public int age { get; set; }
}
第三种:异步赋值
public partial class MainViewModel : ObservableObject
{
private TaskNotifier<int> taskValue;
public Task<int> TaskValue
{
get { return taskValue; }
set
{
// 异步赋值
SetPropertyAndNotifyOnCompletion(ref taskValue, value);
}
}
private void Refresh()
{
TaskValue = new Task<int>(() => { Thread.Sleep(3000); return 1000; });
}
}
RelayCommand/RelayCommand<T>:绑定属性
和MvvmLight一模一样
public RelayCommand BtnCommand { get; set; }
public MainViewModel()
{
BtnCommand = new RelayCommand(()=>{ });
}
Messenger:订阅
WeakReferenceMessenger(弱订阅)/StrongReferenceMessener(强订阅)
public MainViewModel()
{
BtnCommand = new RelayCommand(BtnClick);
// 消息订阅 Token
WeakReferenceMessenger.Default.Register<string, string>(this, "One", (obj, str) =>
{
(obj as MainViewModel).Value = str;
});
WeakReferenceMessenger.Default.Register<string, string>(this, "Two", (obj, str) =>
{
(obj as MainViewModel).Value = str;
});
// 释放
WeakReferenceMessenger.Default.UnregisterAll(this);
}
private void BtnClick()
{
// 触发
WeakReferenceMessenger.Default.Send<string, string>("One", "One");
WeakReferenceMessenger.Default.Send<string, string>("Two", "Two");
}
IOC:容器
默认这个工具包中没有IoC对象,建议使用 ServiceCollection
实例化IOC容器:
// 实例化 IOC容器
static ServiceCollection service = new ServiceCollection();
public static IServiceProvider Service { get; private set; }
添加IOC容器:
service.AddSingleton<MainViewModel>();
Service = service.BuildServiceProvider();
使用IOC容器中的类:
App.Service.GetService<MainViewModel>();
释放IOC容器:
service.RemoveAll<MainViewModel>();
结合关闭当前界面,释放当前ioc容器:
MainViewModel:需要继承IDisposable,重写Dispose 方法:
public class MainViewModel : ObservableObject, IDisposable
{
public void Dispose()
{
// 释放资源
}
}
在APP.xaml(写IOC注入的类)中写清除方法:
public static void Cleanup<T>() where T : IDisposable
{
Service.GetService<T>().Dispose();
service.RemoveAll<T>();
}
在窗体界面调用:
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
App.Cleanup<MainViewModel>();
}
扩展对象
特性
ObservableProperty:通知属性
[ObservableProperty]
public string name;
以上代码等同于:
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
写法注意:一般都是小写,然后工具类中自动变为大写:abcNet --> AbcNet ; _abcNet --> AbcNet ; m_abcNet --> AbcNet
所以,就算字段是name,界面可以直接使用Name来赋值。
注意:当前类需要加partial修饰符,因为当写这个特性的时候,工具类会自动生成一个文件与此类绑定,必须加修饰符进行绑定:
处理当前修饰符特性字段的变化逻辑:
// 如何处理这个字段特性的变化set逻辑/过程
partial void OnNameChanged(string? oldValue, string newValue)
{
// 处理字段变化过程
}
partial void OnNameChanging(string? oldValue, string newValue)
{
// 当字段开始变化时执行
}
NotifyPropertyChangedFor:
修改此属性的时候,通知指定属性
[ObservableProperty]
[NotifyPropertyChangedFor("FullName")]
//NotifyPropertyChangedFor:修改此属性的时候,通知指定属性;
//当更新name的时候,也要更新FullName
public string name;
// 页面绑定的是FullName 属性 ,
private string FullName { get => "xh" + name; }
ObservableValidator:验证
需要验证的类一般继承ObservableValidator,然后一般是写在Model层,不是ViewModel层
NotifyDataErrorInfo:这个特性必须加,否则不会校验,关键的校验特性
其他特性和普通特性一样,没有变化
[ObservableProperty]
[NotifyDataErrorInfo] //NotifyDataErrorInfo:关键的校验特性
[Required(ErrorMessage = "必填")]// 必填项目
[MinLength(1)] // 最小长度
private string inputValue = "123";
NotifyPropertyChangedRecipients:广播通知
[NotifyPropertyChangedRecipients]
class A : ObservableRecipient
{
public string Name { get; set; }
// 广播信息
protected override void Broadcast<T>(T oldValue, T newValue, string? propertyName)
{
base.Broadcast(oldValue, newValue, propertyName);
}
}
RelayCommand:命令
[RelayCommand]
// RelayCommand:自动生成相关内容,可以直接绑定 自动生成name+Command
private void DoButton()
{
}
界面使用:
<Button Content="Btn" Command="{Binding DoButtonCommand}" />
AsyncRelayCommand
异步绑定事件:
public AsyncRelayCommand AsyncButtonCommand { get; set; }
public MainViewModel()
{
AsyncButtonCommand = new AsyncRelayCommand(AsyncButtonClick);
}
// 异步执行绑定
private Task AsyncButtonClick()
{
return Task.Run(() => { });
}
// 以上相当于:
private void BtnClick()
{
Task.Run(() => { });
}
Message相关/ ObservableRecipient
需要继承类:ObservableRecipient,实现接口IRecipient<in TMessage>
在构造函数中,开启消息接收this.IsActive = true;
核心代码如下:
private void BtnClick()
{
// 触发
WeakReferenceMessenger.Default.Send<string>("Hello");
}
// 接受
public void Receive(string message)
{
// message == Hello
}