MVVM模式的核心组成
MVVM模式主要分为三部分,各部分职责边界清晰,能有效降低代码耦合度。Model层负责封装业务数据和核心业务逻辑,不涉及任何界面相关的逻辑;View层就是用户看到的界面,只负责展示数据和响应用户操作,不包含业务逻辑;ViewModel层是连接View和Model的桥梁,负责将Model的数据转换为View能直接绑定的格式,同时处理View传递的用户操作,通知View数据变化。

传统MVVM实现的痛点
如果不使用工具库手动实现MVVM,开发者需要写很多重复代码。比如实现属性变更通知,需要让ViewModel继承INotifyPropertyChanged接口,手动编写属性变更事件触发逻辑;定义命令需要实现ICommand接口,编写CanExecute和Execute方法,代码冗余度很高。
下面是一个传统方式实现ViewModel的示例,仅一个简单的可通知属性就需要多行代码:
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
// 传统方式ViewModel基类
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
{
return false;
}
field = value;
OnPropertyChanged(propertyName);
return true;
}
}
// 传统方式实现具体ViewModel
public class UserViewModel : BaseViewModel
{
private string _userName;
public string UserName
{
get => _userName;
set => SetProperty(ref _userName, value);
}
private ICommand _updateNameCommand;
public ICommand UpdateNameCommand
{
get
{
if (_updateNameCommand == null)
{
_updateNameCommand = new RelayCommand(UpdateName, CanUpdateName);
}
return _updateNameCommand;
}
}
private void UpdateName(object parameter)
{
UserName = parameter?.ToString();
}
private bool CanUpdateName(object parameter)
{
return parameter != null && !string.IsNullOrEmpty(parameter.ToString());
}
}
// 传统方式RelayCommand实现
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
CommunityToolkit.Mvvm简化MVVM实现
CommunityToolkit.Mvvm是微软官方维护的轻量级MVVM库,不需要依赖特定UI框架,支持WPF、WinUI、MAUI等多种C#界面开发场景。它通过特性标记和泛型基类的方式,把传统MVVM中需要手动编写的重复代码全部封装,开发者只需要关注业务逻辑本身。
安装工具库
首先需要通过NuGet安装CommunityToolkit.Mvvm包,在Visual Studio的包管理器控制台执行以下命令即可:
Install-Package CommunityToolkit.Mvvm
简化属性定义
使用ObservableProperty特性标记字段,工具库会在编译时自动生成对应的可通知属性,不需要手动编写属性包装器和变更通知逻辑。同时ObservableObject基类已经实现了INotifyPropertyChanged接口,直接继承即可使用。
下面是使用工具库简化后的属性定义代码:
using CommunityToolkit.Mvvm.ComponentModel;
// 继承ObservableObject基类,自动获得属性变更通知能力
public partial class UserViewModel : ObservableObject
{
// 使用ObservableProperty特性标记字段,自动生成UserName可通知属性
[ObservableProperty]
private string _userName;
}
编译后工具库会自动生成以下等效代码,完全不需要开发者手动编写:
public string UserName
{
get => _userName;
set
{
if (!EqualityComparer<string>.Default.Equals(_userName, value))
{
_userName = value;
OnPropertyChanged(nameof(UserName));
}
}
}
简化命令定义
工具库提供了RelayCommand和AsyncRelayCommand两种命令类型,搭配RelayCommand特性标记方法,就能自动生成对应的命令属性,不需要手动实现ICommand接口。
简化后的命令实现代码如下:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
public partial class UserViewModel : ObservableObject
{
[ObservableProperty]
private string _userName;
// 使用RelayCommand特性标记方法,自动生成UpdateNameCommand命令属性
[RelayCommand(CanExecute = nameof(CanUpdateName))]
private void UpdateName(string newName)
{
UserName = newName;
}
// 命令可执行性判断方法
private bool CanUpdateName(string newName)
{
return !string.IsNullOrEmpty(newName);
}
}
如果需要实现异步命令,只需要把方法改为异步方法,使用AsyncRelayCommand特性即可:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Threading.Tasks;
public partial class UserViewModel : ObservableObject
{
[ObservableProperty]
private string _userName;
// 异步命令示例
[RelayCommand]
private async Task LoadUserNameAsync()
{
// 模拟异步加载数据
await Task.Delay(1000);
UserName = "默认用户";
}
}
消息通信简化
MVVM中不同ViewModel之间经常需要通信,传统方式需要手动定义事件或者使用第三方消息组件,CommunityToolkit.Mvvm内置了轻量级的消息通信机制,通过WeakReferenceMessenger实现,避免内存泄漏问题。
下面是消息发送和接收的示例:
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
// 定义消息类型
public class UserNameChangedMessage : ValueChangedMessage<string>
{
public UserNameChangedMessage(string value) : base(value)
{
}
}
// 发送消息的ViewModel
public partial class ViewModelA : ObservableObject
{
[RelayCommand]
private void SendMessage()
{
WeakReferenceMessenger.Default.Send(new UserNameChangedMessage("新用户名"));
}
}
// 接收消息的ViewModel
public partial class ViewModelB : ObservableObject
{
public ViewModelB()
{
// 注册消息接收
WeakReferenceMessenger.Default.Register<UserNameChangedMessage>(this, (r, m) =>
{
// 处理接收到的消息
var newName = m.Value;
});
}
}
实际开发中的注意事项
使用CommunityToolkit.Mvvm时需要注意,特性标记生成的代码是在编译阶段生成的,所以修改特性标记后需要重新编译才能生效。另外ObservableProperty特性只能标记字段,不能标记属性,字段的命名需要遵循下划线开头的规范,否则生成的属性名称可能不符合预期。如果需要在属性变更时执行额外逻辑,可以重写OnUserNameChanged方法,工具库会自动生成这个部分方法供开发者扩展。
相比传统手动实现MVVM,使用CommunityToolkit.Mvvm能让ViewModel的代码量减少60%以上,同时避免了手动编写重复代码可能出现的逻辑错误,对于中大型C#界面项目来说,能显著提升开发效率和代码可维护性。
C#MVVMCommunityToolkit_Mvvm数据绑定命令修改时间:2026-07-18 21:21:47