====== WPF MVVM 标准示例教程 ====== 理解 WPF 的核心就在于理解 **MVVM (Model-View-ViewModel)** 模式。 在这个例子中,我们将创建一个简单的 **“用户列表管理”** 应用。 * **功能**:输入姓名和年龄,点击添加按钮,列表会实时更新。 * **特点**:完全**不使用**传统的事件处理器(如 `Button_Click`),而是使用 **数据绑定 (Data Binding)** 和 **命令 (Command)**。 ===== 1. 基础架构 (Infrastructure) ===== 在标准的 MVVM 中,我们需要两个辅助类: - **ViewModelBase**: 实现 `INotifyPropertyChanged` 接口,用于通知 UI 数据变了。 - **RelayCommand**: 实现 `ICommand` 接口,用于处理按钮点击逻辑。 using System; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows.Input; namespace WpfMvvmExample { // 1. 通知基类:当属性变化时,告诉 UI 刷新 public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } // 辅助方法:设置值并通知 protected bool SetProperty(ref T field, T value, [CallerMemberName] string propertyName = null) { if (Equals(field, value)) return false; field = value; OnPropertyChanged(propertyName); return true; } } // 2. 命令类:将按钮点击行为绑定到方法 public class RelayCommand : ICommand { private readonly Action _execute; private readonly Predicate _canExecute; public RelayCommand(Action execute, Predicate canExecute = null) { _execute = execute; _canExecute = canExecute; } public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter); public void Execute(object parameter) => _execute(parameter); public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } } } ===== 2. 模型 (Model) ===== 这是纯粹的数据对象,不包含任何 UI 逻辑。 namespace WpfMvvmExample { public class User { public string Name { get; set; } public int Age { get; set; } // 用于显示的格式化字符串 public string DisplayInfo => $"{Name} ({Age}岁)"; } } ===== 3. 视图模型 (ViewModel) ===== 这是 MVVM 的核心。它是 View(界面)和 Model(数据)的桥梁。 * 它持有数据列表 (`ObservableCollection`)。 * 它持有当前输入的字段。 * 它持有命令 (`AddUserCommand`)。 using System.Collections.ObjectModel; using System.Windows; namespace WpfMvvmExample { public class MainViewModel : ViewModelBase { // --- 状态字段 --- private string _inputName; private int _inputAge; // --- 绑定到界面的属性 --- public string InputName { get => _inputName; set => SetProperty(ref _inputName, value); // 值改变时通知 UI } public int InputAge { get => _inputAge; set => SetProperty(ref _inputAge, value); } // ObservableCollection 是 WPF 列表绑定的神器,集合变动会自动刷新界面 public ObservableCollection Users { get; set; } // --- 命令 --- public RelayCommand AddUserCommand { get; set; } // --- 构造函数 --- public MainViewModel() { Users = new ObservableCollection { new User { Name = "张三", Age = 25 } // 初始数据 }; // 初始化命令:指定执行逻辑(AddUser) 和 判断逻辑(CanAddUser) AddUserCommand = new RelayCommand(AddUser, CanAddUser); } // --- 逻辑方法 --- private void AddUser(object obj) { // 添加到集合 Users.Add(new User { Name = InputName, Age = InputAge }); // 清空输入框 InputName = string.Empty; InputAge = 0; } // 判断按钮是否可用(例如:名字不能为空) // 如果返回 false,WPF 会自动禁用按钮 private bool CanAddUser(object obj) { return !string.IsNullOrWhiteSpace(InputName); } } } ===== 4. 视图 (View - XAML) ===== 在 XAML 中,我们**不写任何 C# 代码**来处理逻辑,全部通过 `Binding` 连接到 ViewModel。