欢迎光临
我们一直在努力

WPF入门

✅ WPF 系列第二篇:MVVM 模式与 CommunityToolkit.Mvvm


一、什么是 MVVM?

MVVM(Model-View-ViewModel)是一种架构模式,特别适合 WPF 应用程序开发。它将应用程序分为三个主要部分:

┌─────────────┐
│ View │ ← XAML 界面,负责展示
│ (XAML) │
└──────┬──────┘
│ DataBinding

┌─────────────┐
│ ViewModel │ ← 业务逻辑,连接 View 和 Model
│ (C#) │
└──────┬──────┘


┌─────────────┐
│ Model │ ← 数据模型,业务数据
│ (C#) │
└─────────────┘

MVVM 的优势

  • 分离关注点:界面逻辑与业务逻辑分离
  • 易于测试:ViewModel 可以独立测试
  • 代码复用:同一个 ViewModel 可以绑定到不同的 View
  • 数据绑定:通过数据绑定实现自动更新

二、安装 CommunityToolkit.Mvvm 和配置项目结构

2.1 安装 CommunityToolkit.Mvvm

微软社区提供的 CommunityToolkit.Mvvm 包提供了强大的 MVVM 工具,包括:

  • [ObservableProperty] – 自动生成属性通知
  • [RelayCommand] – 自动生成命令
  • ObservableObject – 可观察对象基类
  • 更多实用特性…

安装步骤:

在 Visual Studio 的 NuGet 包管理器中搜索 CommunityToolkit.Mvvm 并安装。 在这里插入图片描述 在这里插入图片描述

2.2 MVVM 文件夹结构

让我们将项目组织成标准的 MVVM 结构:

WPF_DEMO/
├── Views/ # 视图层(XAML 文件)
│ └── MainWindow.xaml
│ └── MainWindow.xaml.cs
├── ViewModels/ # 视图模型层(业务逻辑)
│ └── MainWindowViewModel.cs
└── Models/ # 数据模型层
└── User.cs

在这里插入图片描述

创建文件夹结构:

  • 在项目中创建三个文件夹:Views、ViewModels、Models
  • 将 MainWindow.xaml 和 MainWindow.xaml.cs 移动到 Views 文件夹
  • 更新命名空间

  • 三、核心特性详解

    3.1 [ObservableProperty] 特性

    [ObservableProperty] 是 MVVM Toolkit 最强大的特性之一。它自动为字段生成属性,并实现 INotifyPropertyChanged 通知。

    传统方式(繁琐)

    private string _name;
    public string Name
    {
    get => _name;
    set
    {
    if (_name != value)
    {
    _name = value;
    OnPropertyChanged(nameof(Name));
    }
    }
    }

    使用 [ObservableProperty](简洁)

    [ObservableProperty]
    private string _name; // 自动生成 Name 属性,并实现属性变更通知

    工作原理:

    • 源生成器会自动生成 Name 属性
    • 自动实现 PropertyChanged 事件通知
    • 支持属性验证和自定义逻辑

    3.2 [RelayCommand] 特性

    [RelayCommand] 自动生成命令属性,用于处理按钮点击等操作。

    传统方式(繁琐)

    private ICommand _submitCommand;
    public ICommand SubmitCommand
    {
    get
    {
    if (_submitCommand == null)
    {
    _submitCommand = new RelayCommand(ExecuteSubmit, CanExecuteSubmit);
    }
    return _submitCommand;
    }
    }

    private void ExecuteSubmit()
    {
    // 执行逻辑
    }

    private bool CanExecuteSubmit()
    {
    return !string.IsNullOrEmpty(UserName);
    }

    使用 [RelayCommand](简洁)

    [RelayCommand]
    private void Submit() // 自动生成 SubmitCommand 属性
    {
    // 执行逻辑
    }

    [RelayCommand(CanExecute = nameof(CanSubmit))]
    private void Submit()
    {
    // 执行逻辑
    }

    private bool CanSubmit() => !string.IsNullOrEmpty(UserName);


    四、示例

    4.1 Model(数据模型)

    // Models/User.cs
    namespace WPF_DEMO.Models
    {
    /// <summary>
    /// 最简单的模型:只包含一个 Name 属性
    /// </summary>
    public class User
    {
    public string Name { get; set; } = string.Empty;
    }
    }

    4.2 ViewModel(视图模型)

    // ViewModels/MainWindowViewModel.cs
    using CommunityToolkit.Mvvm.ComponentModel;
    using CommunityToolkit.Mvvm.Input;
    using WPF_DEMO.Models;

    namespace WPF_DEMO.ViewModels
    {
    public partial class MainWindowViewModel : ObservableObject
    {
    // 一个模型:User(用 ObservableProperty 包起来)
    [ObservableProperty]
    private User _user = new();

    // 一个属性:用于显示问候语
    [ObservableProperty]
    private string _greeting = "请输入姓名,然后点击按钮";

    // 一个命令:点击后根据姓名生成问候语
    [RelayCommand]
    private void SayHello()
    {
    if (string.IsNullOrWhiteSpace(User.Name))
    {
    Greeting = "请先输入姓名";
    }
    else
    {
    Greeting = $"你好,{User.Name}!欢迎学习 MVVM。";
    }
    }
    }
    }

    4.3 View(视图)

    <!– Views/MainWindow.xaml –>
    <Window x:Class="WPF_DEMO.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="clr-namespace:WPF_DEMO.ViewModels"
    mc:Ignorable="d"
    Title="MVVM 最小示例" Height="200" Width="400">

    <Window.DataContext>
    <vm:MainWindowViewModel />
    </Window.DataContext>

    <Grid Margin="20">
    <Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <!– 输入姓名 –>
    <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,10">
    <TextBlock Text="姓名:" VerticalAlignment="Center" Margin="0,0,5,0"/>
    <TextBox Width="200"
    Text="{Binding User.Name, UpdateSourceTrigger=PropertyChanged}"/>

    </StackPanel>

    <!– 按钮 –>
    <Button Grid.Row="1"
    Content="打招呼"
    Width="80"
    HorizontalAlignment="Left"
    Command="{Binding SayHelloCommand}"/>

    <!– 问候语显示 –>
    <TextBlock Grid.Row="2"
    Text="{Binding Greeting}"
    FontSize="14"
    Margin="0,10,0,0"
    TextWrapping="Wrap"/>

    </Grid>
    </Window>

    4.4 View 代码后置

    // Views/MainWindow.xaml.cs
    using System.Windows;
    using WPF_DEMO.ViewModels;

    namespace WPF_DEMO.Views
    {
    public partial class MainWindow : Window
    {
    public MainWindow()
    {
    InitializeComponent();
    DataContext = new MainWindowViewModel();
    }
    }
    }


    4.5 效果

    在这里插入图片描述

    五、小结

    这一篇我们用一个「输入姓名 → 点击按钮 → 显示问候语」的极简示例,把 View / ViewModel / Model 拆开,并且实际演示了 ObservableProperty 和 RelayCommand 的使用方式。

    后续我还会继续分享更完整的 MVVM 示例,比如列表、导航、依赖注入等场景,帮助你一步步把 WPF 项目从 Demo 搞成可以真正上线的应用。

    这就是 WPF 系列的第二篇,如果你想直接看代码或获取后续更新,可以关注我的GitHub主页:https://github.com/leepinkz

    赞(0)
    未经允许不得转载:171主机测评 » WPF入门
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址