MVVM即Model-View-ViewModel,是WPF开发中主流的架构模式,核心目标是通过分层设计将界面展示、业务逻辑、数据模型完全解耦,让各层职责清晰,降低代码耦合度,方便后续维护与单元测试。

MVVM模式的核心组成
MVVM模式分为三个核心部分,各部分职责明确,互不干扰:
- Model:数据模型层,负责封装业务数据和基础的业务逻辑,比如从数据库获取数据、数据校验规则等,不依赖View和ViewModel。
- View:视图层,即WPF的界面XAML文件,负责展示UI元素,不直接编写业务逻辑,仅通过数据绑定和命令绑定与ViewModel交互。
- ViewModel:视图模型层,作为View和Model的中间桥梁,持有Model的实例,将Model的数据转换为View可绑定的属性,同时定义View可触发的命令,处理用户交互逻辑。
基础准备工作
实现MVVM需要先定义基础的通知接口和命令类,让ViewModel能够通知View属性变化,同时支持命令绑定。
实现属性通知接口
ViewModel需要实现INotifyPropertyChanged接口,当属性值变化时通知界面更新,首先定义基础的通知基类:
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace WpfMvvmDemo
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// 属性变化通知方法
protected virtual 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;
}
}
}
实现通用命令类
WPF的命令需要实现ICommand接口,定义通用命令类支持委托绑定:
using System;
using System.Windows.Input;
namespace WpfMvvmDemo
{
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
// 判断命令是否可执行
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
// 执行命令逻辑
public void Execute(object parameter)
{
_execute(parameter);
}
// 可执行状态变化时触发通知
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
}
完整示例实现
下面以一个用户信息展示和更新的场景为例,完整实现MVVM模式的分层与交互。
定义Model层
Model层仅包含用户数据和基础的数据校验逻辑:
namespace WpfMvvmDemo
{
public class UserModel
{
// 用户ID
public int Id { get; set; }
// 用户名称
public string Name { get; set; }
// 用户年龄
public int Age { get; set; }
// 基础数据校验方法
public bool IsValid()
{
return !string.IsNullOrEmpty(Name) && Age > 0;
}
}
}
定义ViewModel层
ViewModel持有UserModel实例,将Model的属性转换为可绑定的属性,同时定义更新用户的命令:
namespace WpfMvvmDemo
{
public class UserViewModel : ViewModelBase
{
private UserModel _user;
private string _message;
public UserViewModel()
{
// 初始化Model数据
_user = new UserModel
{
Id = 1,
Name = "默认用户",
Age = 18
};
// 初始化更新命令
UpdateUserCommand = new RelayCommand(UpdateUser);
}
// 用户属性,供View绑定
public string UserName
{
get { return _user.Name; }
set
{
if (SetProperty(ref _user.Name, value))
{
// 名称变化时更新提示信息
Message = $"用户名称已修改为{value}";
}
}
}
public int UserAge
{
get { return _user.Age; }
set
{
if (SetProperty(ref _user.Age, value))
{
Message = $"用户年龄已修改为{value}";
}
}
}
// 提示信息属性
public string Message
{
get { return _message; }
set { SetProperty(ref _message, value); }
}
// 更新用户命令
public RelayCommand UpdateUserCommand { get; private set; }
// 命令执行逻辑
private void UpdateUser(object parameter)
{
if (_user.IsValid())
{
Message = $"用户信息更新成功,当前用户:{UserName},年龄:{UserAge}";
}
else
{
Message = "用户信息校验失败,请检查名称和年龄是否合法";
}
}
}
}
定义View层
View层即XAML界面,仅做UI布局和绑定,不写任何业务逻辑,通过Binding绑定ViewModel的属性和命令:
<Window x:Class="WpfMvvmDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfMvvmDemo"
Title="MVVM示例" Height="300" Width="400">
<Window.DataContext>
<!-- 设置当前窗口的数据上下文为UserViewModel -->
<local:UserViewModel />
</Window.DataContext>
<Grid Margin="20">
<StackPanel VerticalAlignment="Center">
<TextBlock Text="用户信息" FontSize="16" FontWeight="Bold" Margin="0 0 0 10" />
<StackPanel Orientation="Horizontal" Margin="0 5">
<TextBlock Text="名称:" Width="60" VerticalAlignment="Center" />
<TextBox Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged}" Width="200" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0 5">
<TextBlock Text="年龄:" Width="60" VerticalAlignment="Center" />
<TextBox Text="{Binding UserAge, UpdateSourceTrigger=PropertyChanged}" Width="200" />
</StackPanel>
<Button Content="更新用户信息" Command="{Binding UpdateUserCommand}" Margin="0 10 0 10" Width="150" Height="30" />
<TextBlock Text="{Binding Message}" Foreground="Blue" Margin="0 10 0 0" TextWrapping="Wrap" />
</StackPanel>
</Grid>
</Window>
运行效果与验证
编译运行程序后,界面会显示默认的用户名称和年龄,修改输入框的内容时,ViewModel的属性会同步更新,点击更新按钮会触发命令逻辑,校验数据后返回对应的提示信息。整个过程中,View层没有编写任何C#业务逻辑代码,所有交互逻辑都在ViewModel中处理,Model层仅负责数据本身,完全实现了视图和逻辑的分离。
MVVM模式的优势
- 低耦合:View和ViewModel通过数据绑定交互,没有直接的代码依赖,修改界面不会影响业务逻辑,修改逻辑也不需要调整界面代码。
- 可测试性:ViewModel不依赖UI元素,可以直接编写单元测试验证业务逻辑,不需要启动界面即可测试。
- 可维护性:分层清晰,代码结构明确,后续迭代时更容易定位问题和扩展功能。