以下从无框架 、Prism 框架 、CommunityToolkit.Mvvm 框架三个维度,通过具体场景(以 "带导航的用户信息展示" 为例)对比其实现差异,并总结核心区别。
一、核心区别总览
| 维度 | 无框架(原生 WPF) | CommunityToolkit.Mvvm | Prism |
|---|---|---|---|
| 设计模式支持 | 需手动实现 MVVM(接口 + 事件) | 封装 MVVM 核心(ObservableObject 等) | 完整 MVVM + 额外企业级功能(区域、导航等) |
| 依赖注入 | 无原生支持,需手动实例化对象 | 无内置 IOC,可配合第三方(如 Autofac) | 内置 DryIoc/Unity 容器 |
| 导航与区域 | 需手动控制 Frame/ContentControl 切换 | 无内置支持,需手动实现 | 区域管理(Region)+ 导航服务 |
| 命令系统 | 需手动实现 ICommand | RelayCommand/AsyncRelayCommand | DelegateCommand/CompositeCommand |
| 视图与 VM 关联 | 手动设置 DataContext | 自动关联(需约定)+ViewModelLocator | 自动关联(约定)+Region 导航 |
| 适用场景 | 小型 demo、学习原生机制 | 中小型 MVVM 项目,轻量需求 | 大型复杂应用(模块化、多区域、团队协作) |
二、详细示例对比(同一功能实现)
以 "一个主窗口包含导航按钮,点击按钮切换不同用户信息页面(UserInfoView),页面展示用户名称并支持修改" 为例。
1. 无框架(原生 WPF)实现
需手动实现INotifyPropertyChanged、ICommand,手动管理页面切换。
(1)模型(User.cs)
public class User
{
public string Name { get; set; }
}
(2)视图模型(UserInfoViewModel.cs)
需手动实现属性通知和命令:
using System.ComponentModel;
using System.Windows.Input;
public class UserInfoViewModel : INotifyPropertyChanged
{
private User _user;
public User User
{
get => _user;
set
{
_user = value;
OnPropertyChanged(nameof(User));
}
}
// 手动实现ICommand
public ICommand UpdateNameCommand { get; }
public UserInfoViewModel()
{
User = new User { Name = "初始用户" };
UpdateNameCommand = new UpdateNameCommand(this);
}
// 手动实现属性通知
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
// 自定义命令(需手动实现ICommand)
public class UpdateNameCommand : ICommand
{
private readonly UserInfoViewModel _vm;
public event EventHandler CanExecuteChanged;
public UpdateNameCommand(UserInfoViewModel vm) => _vm = vm;
public bool CanExecute(object parameter) => true;
public void Execute(object parameter)
{
_vm.User.Name = "修改后的用户";
_vm.OnPropertyChanged(nameof(_vm.User)); // 需手动触发通知
}
}
(3)视图(UserInfoView.xaml)
手动设置 DataContext:
<UserControl x:Class="WpfNoFramework.UserInfoView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<StackPanel>
<TextBlock Text="{Binding User.Name}"/>
<Button Content="修改名称" Command="{Binding UpdateNameCommand}"/>
</StackPanel>
</UserControl>
(4)主窗口(MainWindow.xaml)
用 Frame 手动切换页面:
<Window x:Class="WpfNoFramework.MainWindow">
<Grid>
<Button Content="显示用户信息" Click="ShowUserInfo_Click"/>
<Frame x:Name="MainFrame" Margin="0,50,0,0"/>
</Grid>
</Window>
(5)主窗口后台(MainWindow.xaml.cs)
手动实例化 VM 和视图:
private void ShowUserInfo_Click(object sender, RoutedEventArgs e)
{
// 手动关联VM和视图
var view = new UserInfoView();
view.DataContext = new UserInfoViewModel();
MainFrame.Content = view; // 手动切换页面
}
2. CommunityToolkit.Mvvm 实现
框架封装了 MVVM 核心功能,简化属性通知和命令,但需手动处理导航。
(1)安装包
Install-Package CommunityToolkit.Mvvm
(2)视图模型(UserInfoViewModel.cs)
使用框架基类和命令:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
// 继承ObservableObject(自动实现INotifyPropertyChanged)
public partial class UserInfoViewModel : ObservableObject
{
[ObservableProperty] // 自动生成属性和通知
private User _user = new User { Name = "初始用户" };
// 自动生成RelayCommand(无需手动实现ICommand)
[RelayCommand]
private void UpdateName()
{
User.Name = "修改后的用户";
// 无需手动触发通知,[ObservableProperty]自动处理
}
}
(3)视图(UserInfoView.xaml)
自动关联 VM(需遵循约定:View 在 Views 文件夹,VM 在 ViewModels 文件夹,名称对应):
<UserControl x:Class="ToolkitDemo.Views.UserInfoView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:vm="clr-namespace:ToolkitDemo.ViewModels">
<!-- 若不遵循约定,需手动设置DataContext:DataContext="{x:Type vm:UserInfoViewModel}" -->
<StackPanel>
<TextBlock Text="{Binding User.Name}"/>
<Button Content="修改名称" Command="{Binding UpdateNameCommand}"/>
</StackPanel>
</UserControl>
(4)主窗口导航(MainWindow.xaml.cs)
仍需手动切换页面(框架无内置导航):
private void ShowUserInfo_Click(object sender, RoutedEventArgs e)
{
// 无需手动实例化VM,框架自动关联(基于约定)
MainFrame.Content = new Views.UserInfoView();
}
3. Prism 框架实现
除 MVVM 核心外,提供区域管理、导航服务、IOC 容器等企业级功能。
(1)安装包
Install-Package Prism.DryIoc
(2)配置 App(继承 PrismApplication)
// App.xaml.cs
using Prism.Ioc;
using Prism.Modularity;
using System.Windows;
public partial class App : PrismApplication
{
// 指定主窗口
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
// 注册服务和视图(支持导航)
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<UserInfoView, UserInfoViewModel>();
}
}
(3)视图模型(UserInfoViewModel.cs)
使用 Prism 的基类和命令:
using Prism.Commands;
using Prism.Mvvm;
public class UserInfoViewModel : BindableBase
{
private User _user;
public User User
{
get => _user;
set => SetProperty(ref _user, value); // Prism的SetProperty自动触发通知
}
public DelegateCommand UpdateNameCommand { get; }
public UserInfoViewModel()
{
User = new User { Name = "初始用户" };
UpdateNameCommand = new DelegateCommand(UpdateName);
}
private void UpdateName()
{
User.Name = "修改后的用户";
}
}
(4)主窗口(MainWindow.xaml)
使用 Prism 区域(Region)作为容器:
<Window x:Class="PrismDemo.MainWindow"
xmlns:prism="http://prismlibrary.com/">
<Grid>
<!-- 导航按钮(绑定命令) -->
<Button Content="显示用户信息"
Command="{Binding NavigateCommand}"
CommandParameter="UserInfoView"/>
<!-- 区域容器(用于动态加载视图) -->
<ContentControl prism:RegionManager.RegionName="MainRegion"
Margin="0,50,0,0"/>
</Grid>
</Window>
(5)主窗口 VM(MainWindowViewModel.cs)
通过 Prism 导航服务切换视图:
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
public class MainWindowViewModel : BindableBase
{
private readonly IRegionManager _regionManager;
// 导航命令
public DelegateCommand<string> NavigateCommand { get; }
// 依赖注入区域管理器
public MainWindowViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
NavigateCommand = new DelegateCommand<string>(Navigate);
}
// 调用Prism导航服务切换区域内容
private void Navigate(string viewName)
{
_regionManager.RequestNavigate("MainRegion", viewName);
}
}
三、示例核心差异总结
| 实现环节 | 无框架 | CommunityToolkit.Mvvm | Prism |
|---|---|---|---|
| 属性通知 | 手动实现INotifyPropertyChanged |
ObservableObject+[ObservableProperty] |
BindableBase+SetProperty |
| 命令实现 | 手动实现ICommand接口 |
[RelayCommand]自动生成 |
DelegateCommand |
| 视图 - VM 关联 | 手动设置DataContext |
约定优先(文件夹 + 命名) | 约定优先 + 区域导航自动关联 |
| 页面导航 | 手动操作Frame.Content |
需手动实现(无内置导航) | 区域管理器(IRegionManager)+ 导航服务 |
| 依赖注入 | 无,手动new对象 |
无内置,需第三方容器 | 内置IContainerRegistry |
| 代码量 | 最大(重复实现接口) | 中等(仅封装 MVVM 核心) | 中等(但功能更全面) |
四、选择建议
-
无框架:适合学习 WPF 原生机制,或开发极简单的 demo。
-
CommunityToolkit.Mvvm:适合中小型 MVVM 项目,需要轻量、高效的 MVVM 核心功能,无需复杂导航和模块化。
-
Prism:适合大型企业级应用,需要模块化开发、多区域管理、复杂导航和团队协作,可显著降低耦合度。