编辑
2025-11-25
C#
00

目录

Nuget 安装CommunityToolkit.Mvvm
基本概念
详细示例
基本使用示例
多属性联动示例
最佳实践
注意事项
结论

在 MVVM 架构中,属性变更通知是保持视图和模型同步的关键机制。NotifyPropertyChangedFor 特性是 CommunityToolkit.Mvvm 提供的一个强大工具,它允许我们在一个属性发生变更时,自动触发其他相关属性的通知。

Nuget 安装CommunityToolkit.Mvvm

image.png

基本概念

NotifyPropertyChangedFor 特性的主要作用是:

  • 当装饰的属性发生变更时,自动触发其他指定属性的 PropertyChanged 事件
  • 减少手动编写属性通知的重复代码
  • 简化属性依赖关系的管理

详细示例

基本使用示例

C#
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace App6 { public partial class UserProfileViewModel : ObservableObject { // 使用 [ObservableProperty] 和 [NotifyPropertyChangedFor] 特性 [ObservableProperty] [NotifyPropertyChangedFor(nameof(FullName))] [NotifyPropertyChangedFor(nameof(IsNameValid))] private string _firstName; [ObservableProperty] [NotifyPropertyChangedFor(nameof(FullName))] [NotifyPropertyChangedFor(nameof(IsNameValid))] private string _lastName; [ObservableProperty] private DateTime _birthDate; // 依赖属性:当 FirstName 或 LastName 变更时,FullName 也会触发通知 public string FullName => $"{_firstName} {_lastName}".Trim(); // 验证姓名是否有效的计算属性 public bool IsNameValid => !string.IsNullOrWhiteSpace(_firstName) && !string.IsNullOrWhiteSpace(_lastName); // 计算年龄的属性 public int Age { get { var today = DateTime.Today; var age = today.Year - _birthDate.Year; if (_birthDate.Date > today.AddYears(-age)) age--; return age; } } // 构造函数 public UserProfileViewModel() { _firstName = string.Empty; _lastName = string.Empty; _birthDate = DateTime.Today.AddYears(-25); // 默认设置为25岁 } // 重置方法 [RelayCommand] private void ResetProfile() { FirstName = string.Empty; LastName = string.Empty; BirthDate = DateTime.Today.AddYears(-25); } // 保存配置文件的命令 [RelayCommand(CanExecute = nameof(IsNameValid))] private void SaveProfile() { // 实际保存逻辑(这里只是示例) Console.WriteLine($"保存用户配置:{FullName}, 年龄:{Age}"); } // 验证方法 public bool ValidateProfile() { return IsNameValid && Age >= 18; } // 格式化显示方法 public string GetFormattedProfile() { return $"姓名:{FullName}\n" + $"年龄:{Age}\n" + $"出生日期:{BirthDate:yyyy-MM-dd}"; } } }
C#
internal class Program { static void Main(string[] args) { var viewModel = new UserProfileViewModel(); // 演示属性变更 viewModel.FirstName = "张"; viewModel.LastName = "三"; viewModel.BirthDate = DateTime.Today.AddYears(-30); // 使用命令 viewModel.SaveProfileCommand.Execute(null); // 输出格式化信息 Console.WriteLine(viewModel.GetFormattedProfile()); // 重置配置 viewModel.ResetProfileCommand.Execute(null); } }
C#
// 产品管理器,演示集合操作 public class ProductManager { // 产品集合 public ObservableCollection<ProductViewModel> Products { get; } = new(); // 添加产品 public void AddProduct(ProductViewModel product) { if (product.ValidateProduct()) { Products.Add(product); } } // 计算总库存价值 public decimal CalculateTotalInventoryValue() { decimal total = 0; foreach (var product in Products) { total += product.TotalPrice; } return total; } }
C#
static void Main(string[] args) { // 创建产品 var laptop = new ProductViewModel { ProductName = "高性能笔记本", Price = 1200, Quantity = 5, Weight = 2.5 }; // 应用折扣 laptop.ApplyDiscountCommand.Execute(0.1m); // 10%折扣 // 输出产品详情 Console.WriteLine(laptop.GetProductDetails()); // 产品管理 var manager = new ProductManager(); manager.AddProduct(laptop); // 计算总库存价值 Console.WriteLine($"总库存价值:{manager.CalculateTotalInventoryValue():C}"); }

image.png

多属性联动示例

C#
public partial class ProductViewModel : ObservableObject { // 价格属性,影响总价和高级产品状态 [ObservableProperty] [NotifyPropertyChangedFor(nameof(TotalPrice))] [NotifyPropertyChangedFor(nameof(IsPremiumProduct))] [NotifyPropertyChangedFor(nameof(DiscountAmount))] private decimal _price; // 数量属性,影响总价 [ObservableProperty] [NotifyPropertyChangedFor(nameof(TotalPrice))] [NotifyPropertyChangedFor(nameof(TotalWeight))] private int _quantity; // 重量属性 [ObservableProperty] private double _weight; // 产品名称 [ObservableProperty] private string _productName; // 折扣率 [ObservableProperty] [NotifyPropertyChangedFor(nameof(DiscountAmount))] private decimal _discountRate; // 总价格:当价格或数量变更时,自动通知 public decimal TotalPrice => _price * _quantity; // 总重量:当数量变更时,自动通知 public double TotalWeight => _weight * _quantity; // 高级产品判断:当价格变更时,自动通知 public bool IsPremiumProduct => _price > 1000; // 折扣金额:当价格或折扣率变更时,自动通知 public decimal DiscountAmount => _price * _discountRate; // 最终价格:考虑折扣 public decimal FinalPrice => TotalPrice - DiscountAmount; // 库存状态 public bool IsInStock => _quantity > 0; // 构造函数 public ProductViewModel() { _price = 0; _quantity = 0; _weight = 0; _productName = string.Empty; _discountRate = 0; } // 添加库存命令 [RelayCommand] private void AddStock(int additionalQuantity) { if (additionalQuantity > 0) { Quantity += additionalQuantity; } } // 移除库存命令 [RelayCommand(CanExecute = nameof(IsInStock))] private void RemoveStock(int removeQuantity) { if (removeQuantity > 0 && removeQuantity <= _quantity) { Quantity -= removeQuantity; } } // 应用折扣命令 [RelayCommand] private void ApplyDiscount(decimal discountPercentage) { if (discountPercentage >= 0 && discountPercentage <= 1) { DiscountRate = discountPercentage; } } // 产品验证方法 public bool ValidateProduct() { return !string.IsNullOrWhiteSpace(_productName) && _price > 0 && _quantity >= 0; } // 获取产品详情 public string GetProductDetails() { return $"产品:{_productName}\n" + $"单价:{_price:C}\n" + $"数量:{_quantity}\n" + $"总价:{TotalPrice:C}\n" + $"折扣:{DiscountAmount:C}\n" + $"最终价格:{FinalPrice:C}\n" + $"是否为高级产品:{IsPremiumProduct}"; } }

image.png

最佳实践

  1. 使用 [ObservableProperty] 结合 [NotifyPropertyChangedFor]
  2. 仅在必要时使用,避免过度复杂的属性依赖
  3. 保持属性计算逻辑简单明了
  4. 考虑性能,不要在复杂的计算属性中执行耗时操作

注意事项

  • NotifyPropertyChangedFor 仅在使用源生成器时有效
  • 确保使用 partial 类和 ObservableObject 基类
  • 属性必须是私有字段,并使用下划线前缀命名

结论

NotifyPropertyChangedFor 特性是 CommunityToolkit.Mvvm 中简化属性变更通知的强大工具。通过智能地使用这一特性,可以编写更简洁、更易维护的 MVVM 代码。

希望这篇文章对你理解和使用 NotifyPropertyChangedFor 有所帮助!

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!