WPF中无框架、Prism 框架、CommunityToolkit.Mvvm 框架的区别

以下从无框架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)实现

需手动实现INotifyPropertyChangedICommand,手动管理页面切换。

(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:适合大型企业级应用,需要模块化开发、多区域管理、复杂导航和团队协作,可显著降低耦合度。

相关推荐
热心市民☆7 小时前
C#基础语法
c#
rainmanqqst7 小时前
C#Netcore支持Https
网络协议·http·https·c#
张人玉13 小时前
Prism 框架笔记及实例
c#·wpf·prism
·心猿意码·13 小时前
告别版本地狱:C# 中央包管理
c#
k***459913 小时前
C#数据库操作系列---SqlSugar完结篇
网络·数据库·c#
lzhdim13 小时前
C#开发的应用启动菜单应用(普通版) - 开源研究系列文章 - 个人小作品
开发语言·c#
MM_MS14 小时前
C# 线程与并发编程完全指南:从基础到高级带详细注释版(一篇读懂)
开发语言·机器学习·计算机视觉·c#·简单工厂模式·visual studio
公子小六16 小时前
推荐一种手动设置异步线程等待机制的解决方案
windows·microsoft·c#·.net
code bean17 小时前
【C++】全局函数和全局变量
开发语言·c++·c#