You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CommunityToolkit.MVVM:ObservableValidator特性报错及导航适配咨询

解决ObservableValidator特性使用错误与NavigationService适配问题

问题场景

将ViewModel的[ObservableObject]特性替换为[ObservableValidator]时,触发编译器错误:

Error CS0653 Cannot apply attribute class 'ObservableValidator' because it is abstract

原可正常运行的ViewModel代码

[ObservableObject]
internal sealed partial class AddSimCardViewModel : ViewModelBase
{
    private readonly NavigationService _addSimCardViewNavigationService;

    [ObservableProperty]
    private string? _phoneNumber;
    
    public AddSimCardViewModel(NavigationService addSimCardViewNavigationService)
    {
        _addSimCardViewNavigationService = addSimCardViewNavigationService;        
    }
}

触发错误的ViewModel代码

[ObservableValidator]
internal sealed partial class AddSimCardViewModel : ViewModelBase
{
    private readonly NavigationService _addSimCardViewNavigationService;

    [ObservableProperty]
    private string? _phoneNumber;
    
    public AddSimCardViewModel(NavigationService addSimCardViewNavigationService)
    {
        _addSimCardViewNavigationService = addSimCardViewNavigationService;        
    }
}

无效的尝试写法

以下两种写法均无法运行,因为ObservableObject和ObservableValidator都是基类,不能作为接口实现:

internal sealed partial class AddSimCardViewModel : ViewModelBase, ObservableObject
internal sealed partial class AddSimCardViewModel : ViewModelBase, ObservableValidator

核心问题分析

ObservableValidator不是特性类,而是抽象基类,不能像ObservableObject那样用特性标记使用。要实现验证功能,需要让ViewModel继承ObservableValidator,但又要保留导航所需的ViewModelBase继承关系,因此需要调整类的继承层次。

解决方案

步骤1:调整ViewModelBase的继承关系

让ViewModelBase继承ObservableValidator,这样所有ViewModel子类既能拥有导航基础功能,又能实现验证能力:

internal class ViewModelBase : ObservableValidator 
{
    public virtual void Dispose() { }
}

步骤2:修正ViewModel代码

移除[ObservableValidator]特性,因为ViewModel已经通过ViewModelBase间接继承了ObservableValidator,同时保留[ObservableProperty]特性来自动生成属性,还可以直接添加验证特性:

internal sealed partial class AddSimCardViewModel : ViewModelBase
{
    private readonly NavigationService _addSimCardViewNavigationService;

    [ObservableProperty]
    [Required(ErrorMessage = "手机号不能为空")]
    private string? _phoneNumber;
    
    public AddSimCardViewModel(NavigationService addSimCardViewNavigationService)
    {
        _addSimCardViewNavigationService = addSimCardViewNavigationService;        
    }
}

步骤3:保持NavigationService与NavigationStore不变

原有的NavigationService和NavigationStore无需修改,因为它们依赖的ViewModelBase现在已经兼容验证功能,所有ViewModel依然是ViewModelBase的子类,导航逻辑不受影响。

原NavigationService代码:

internal sealed class NavigationService
{
    private readonly NavigationStore _navigationStore;
    private readonly Func<ViewModelBase> _createViewModel;

    public NavigationService(NavigationStore navigationStore,
                           Func<ViewModelBase> createViewModel)
    {
        _navigationStore = navigationStore;
        _createViewModel = createViewModel;
    }
    internal void Navigate()
    {
        _navigationStore.CurrentViewModel = _createViewModel();
    }
}

原NavigationStore代码:

internal sealed class NavigationStore
{
    private ViewModelBase _currentViewModel;
    internal ViewModelBase CurrentViewModel
    {
        get => _currentViewModel;
        set
        {
            _currentViewModel?.Dispose();
            _currentViewModel = value;
            OnCurrentViewModelChanged();
        } 
    }

    public event Action CurrentViewModelChanged;

    private void OnCurrentViewModelChanged()
    {
        CurrentViewModelChanged?.Invoke();
    }
}

备选方案(不修改ViewModelBase时)

如果不想让ViewModelBase继承ObservableValidator,可以创建两个基类分支:

  1. 保留原ViewModelBase用于无需验证的ViewModel
  2. 创建ValidatableViewModelBase继承ViewModelBase和ObservableValidator,用于需要验证的ViewModel

然后修改NavigationService为泛型,支持不同的ViewModel基类:

internal sealed class NavigationService<TViewModel> where TViewModel : ViewModelBase
{
    private readonly NavigationStore _navigationStore;
    private readonly Func<TViewModel> _createViewModel;

    public NavigationService(NavigationStore navigationStore,
                           Func<TViewModel> createViewModel)
    {
        _navigationStore = navigationStore;
        _createViewModel = createViewModel;
    }
    internal void Navigate()
    {
        _navigationStore.CurrentViewModel = _createViewModel();
    }
}

对应的ValidatableViewModelBase:

internal class ValidatableViewModelBase : ViewModelBase, ObservableValidator
{
    // 可添加通用验证逻辑
}

此时需要验证的ViewModel继承ValidatableViewModelBase,无需验证的继承原ViewModelBase,导航时使用对应的泛型NavigationService。


内容的提问来源于stack exchange,提问作者JCL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 11:35:22