微软CommunityToolkit.Mvvm和DevExpress中GenerateViewModel使用

1 微软:CommunityToolkit.Mvvm

平台无关:无界面,专门给 WPF、WinForms、UWP、WinUI、MAUI、Avalonia 等桌面 / XAML 框架做 MVVM 分层开发

微软官方维护的MVVM架构轻量级库

使用方式:

​ 1.partial修饰ViewModel继承类ObservableObject,需要Nuget包:Microsoft.Toolkit.Mvvm;

​ 2.属性字段(eg:private string name;)使用标签ObservableProperty,编译自动生成完整属性+通知;可与NotifyCanExecuteChangedFor(nameof(AddCommand))标签结合使用,属性变化,通知命令刷新 CanExecute 状态,控制按钮 IsEnabled,与之相似的还有NotifyPropertyChangedFor,属性变化,通知其他属性刷新 UI;

c# 复制代码
//第一种
date_End.DataBindings.Add(nameof(date_End.EditValue), FViewModel, nameof(FViewModel.Tenant.EndDate), false, DataSourceUpdateMode.OnPropertyChanged);
//第二种
date_End.DataBindings.Add(new Binding(nameof(date_End.EditValue), FViewModel.Tenant, nameof(FViewModel.Tenant.EndDate), false, DataSourceUpdateMode.OnPropertyChanged));

​ 3.方法(eg:Save())使用标签RelayCommand,编译自动生成命令(eg:SaveCommand);

​ 4.CanExecute 控制按钮是否可用;

c# 复制代码
//ViewModel
//1.定义控制IsEnabled的属性;
private bool CanAdd => !string.IsNullOrEmpty(Name) && Age >= 18 && Age <= 70 && Rent >= 0 && EndDate >= StartDate;
//2.命令特性中设置CanExecute
[RelayCommand(CanExecute = nameof(CanAdd))]
public void Add(){......}
//3.涉及到的属性添加
[NotifyCanExecuteChangedFor(nameof(AddCommand))]

//项目中
//4.进行相关绑定
//添加按钮是否可点击CanExecute
FViewModel.AddCommand.CanExecuteChanged += (s, e) => btn_Add.Enabled = FViewModel.AddCommand.CanExecute(null);
btn_Add.Enabled = FViewModel.AddCommand.CanExecute(null);

​ 5.VM之间/VM和界面之间可通过内置消息总线 Messenger(组件解耦)进行通信(1.定义消息实现ValueChangedMessage,T为消息内容;2.VM订阅或发布消息,需继承 ObservableRecipient + 实现 IRecipient<T>,构造函数里 OnActivated() 完成弱引用注册(Receive(T msg){//消息存放在msg.Value中} 方法即回调,获取发布的消息)/ 通过订阅WeakReferenceMessenger.Default.Register(this, (recipient, msg) =>{//消息存放在msg.Value中});3.发布消息:Messenger.Default.Send或WeakReferenceMessenger.Default.Send;

1.1 异常记录

1.控件和ViewModel双向绑定,若是使用嵌套属性绑定,更新存在问题:控件绑定Tenant.Name,当Tenant更新时,控件内容不变;

2.Messenger使用时,使用WeakReferenceMessenger对象发布消息,ViewModel中的Receive可以获得消息,Messenger发布获取不到,经过测试发现,Messenger的命名空间是DevExpress.Mvvm,当前包中只有IMessenger;

2 DevExpress:GenerateViewModel

DevExpress 对标微软 CommunityToolkit.Mvvm 源生成器技术的新一代 MVVM 实现

发展:继承ViewModelBase ➡ POCOViewModel(项目创建默认,中间类动态生成,异常追踪困难)➡ GenerateViewModel(中间类编译生成,性能更好)

使用方式:

​ 1.partial 分部类,打上类级特性GenerateViewModel,需要Nuget包:DevExpress.Mvvm.CodeGenerators(当前最新版本:22.1.1,独立开源,与Dev解耦);

​ 2.字段标记GenerateProperty,编译自动生成属性+INotifyPropertyChanged通知,注意首字母小写,否则编译异常;

​ 3.方法标记GenerateCommand,若需要异步命令GenerateCommand(AllowAsync = true),自动生成命令;

​ 4.支持自动实现 IDataErrorInfo 校验(WPF可以直接使用)、父子 ViewModel 关联(GenerateViewModel(ImplementISupportParentViewModel = false))、DX 服务注入接口(ISupportServices接口,有了这个接口,你的 ViewModel 就可以调用扩展方法:this.GetService<T>() 获取 DX 内置服务);

c# 复制代码
IDataErrorInfo(System.ComponentModel.DataAnnotations):
[Required(ErrorMessage = "")]
[StringLength(20, ErrorMessage = "最多20字符")]
[Range(1,100, ErrorMessage = "年龄必须1‑100")]

​ 5.Messenger通信,注意需要先订阅,后发布,这样才能获取到信息;

c# 复制代码
//先执行,viewmodel使用this也行
Messenger.Default.Register<信息>(viewmodel, m => {//针对信息的处理,m=信息对象});
//后执行
Messenger.Default.Send(信息);
//注意,最后要取消订阅
Messenger.Default.Unregister(viewModel);

​ 6.winform程序需要特殊组件:MVVMContext

c# 复制代码
void InitializeBindings()
{
  // Initialize bindings for EditView
  //mvvmContext1.ViewModelType = typeof(EditViewModel);
  var bFluent = mvvmContext1.OfType<EditViewModel>();
  //fViewModel = bFluent.ViewModel;
  fViewModel = new EditViewModel();
  mvvmContext1.SetViewModel(typeof(EditViewModel), fViewModel);

  // 订阅信息
  Messenger.Default.Register<Tenant>(fViewModel, m =>
  {
    fViewModel.Tenant = m;
    fViewModel.Title = $"编辑租户:{m.Name}";
  });
  //Messenger.Default.Register<Tenant>(fViewModel, m => fViewModel.LoadTenant(m));

  bFluent.SetBinding(this, view => view.Text, x => x.Title);
  bFluent.SetBinding(lbl_Message, l => l.Text, x => x.Message);
  bFluent.SetBinding(txt_Name, t => t.EditValue, x => x.Tenant.Name);
  bFluent.SetBinding(cmb_Sex, c => c.EditValue, x => x.Tenant.Sex);
  bFluent.SetBinding(txt_Age, t => t.EditValue, x => x.Tenant.Age);
  bFluent.SetBinding(txt_Rent, t => t.EditValue, x => x.Tenant.Rent);
  bFluent.SetBinding(date_Start, d => d.EditValue, x => x.Tenant.StartDate);
  bFluent.SetBinding(date_End, d => d.EditValue, x => x.Tenant.EndDate);
  bFluent.BindCommand(btn_Save, x => x.Save);
}

​ 7.控制按钮IsEnable(CanExecute,只针对桌面程序)

c# 复制代码
//1.按钮点击命令
[GenerateCommand]
public void Add() {
  ......
}
//2.按钮事件是否可用
public bool CanAdd() => !string.IsNullOrEmpty(SearchText);
//3.相关属性变更事件
public void OnSearchTextChanged() => AddCommand.RaiseCanExecuteChanged();

2.1 异常记录

1.GenerateCommandGenerateViewModelGenerateProperty使用略有不同,后两个特性可以正常添加,GenerateCommand特性添加时,若没有安装DevExpress.Mvvm包,会有异常:未找到类型或命名空间

2.Messenger通信,注意需要先订阅,后发布,这样才能获取到信息;

相关推荐
曹牧11 分钟前
C#:24小时制时间
c#
唐青枫6 小时前
别急着拆服务:C#.NET 微服务架构从边界设计到实战
c#·.net
czhc114007566310 小时前
从一份运行日志还原一次生产卡死:三个信号与一场“假卡死“
c#
Jazz_z10 小时前
如何用 C# 读取 Word 中的表格数据
开发语言·c#
阿松爱学习12 小时前
【Unity开发】FileStream 详解及用法指南
unity·c#·unity开发
淡海水14 小时前
12-02-性能-数据结构性能调查案例1-5
数据结构·性能优化·c#
Java的搬运工14 小时前
使用 C# 轻松管理 PDF 文件的用户权限
c#·用户权限
Neil20131 天前
ajax跨域请求
c#
唐青枫1 天前
别把 Razor 当成几段 HTML:C#.NET Razor Pages、MVC 视图与实战详解
c#·.net
专注仿真1 天前
CMO模型文档-活动单元基类
c#·模型·cmo·活动单元基类