6.3 ViewModel的实现
核心概念
ViewModel是MVVM模式中的关键组件,负责:
- 封装业务逻辑和状态管理
- 提供数据绑定所需的属性和命令
- 保持与View的松耦合关系
基本实现步骤
1. 创建ViewModel基类
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
2. 实现典型ViewModel
public class ProductViewModel : ViewModelBase
{
private string _productName;
private decimal _price;
public string ProductName
{
get => _productName;
set
{
_productName = value;
OnPropertyChanged();
}
}
public decimal Price
{
get => _price;
set
{
_price = value;
OnPropertyChanged();
}
}
}
高级实现技巧
依赖注入集成
public class MainViewModel
{
private readonly IDataService _dataService;
public MainViewModel(IDataService dataService)
{
_dataService = dataService;
}
}
异步操作处理
public class AsyncViewModel : ViewModelBase
{
private bool _isLoading;
private ICommand _loadDataCommand;
public bool IsLoading
{
get => _isLoading;
set
{
_isLoading = value;
OnPropertyChanged();
}
}
public ICommand LoadDataCommand => _loadDataCommand ??= new AsyncCommand(LoadDataAsync);
private async Task LoadDataAsync()
{
IsLoading = true;
try {
// 异步数据加载
}
finally {
IsLoading = false;
}
}
}
最佳实践
关注点分离:
- 避免在ViewModel中包含UI相关逻辑
- 将复杂业务逻辑委托给领域服务
可测试性设计:
- 保持无状态设计
- 使用接口依赖而非具体实现
性能优化:
- 合理使用延迟加载
- 避免频繁的属性通知
错误处理:
- 实现统一的错误处理机制
- 提供用户友好的错误信息
常见模式
父子ViewModel通信
public class ParentViewModel
{
public ChildViewModel Child { get; }
public ParentViewModel()
{
Child = new ChildViewModel();
Child.PropertyChanged += (s, e) =>
{
if(e.PropertyName == nameof(ChildViewModel.IsValid))
{
// 响应子ViewModel变化
}
};
}
}
消息总线模式
// 使用Messenger或EventAggregator
messenger.Register<DataUpdatedMessage>(this, message =>
{
// 处理消息
});
框架集成示例
使用Prism框架
public class PrismViewModel : BindableBase
{
private string _title;
private readonly IEventAggregator _eventAggregator;
public string Title
{
get => _title;
set => SetProperty(ref _title, value);
}
public PrismViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
}
调试技巧
- 输出绑定错误:
<Window ...
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
TextBlock.Text="{Binding Path, diag:PresentationTraceSources.TraceLevel=High}">
- 设计时数据:
<Window ...
d:DataContext="{d:DesignInstance local:DesignTimeViewModel}">
- ViewModel状态检查:
- 使用DebuggerDisplay特性
- 实现ToString()方法输出关键状态
[DebuggerDisplay("Product: {ProductName} (${Price})")]
public class ProductViewModel : ViewModelBase
{
public override string ToString() => $"{ProductName} - {Price:C}";
}
