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

当ItemsControl存在验证错误时禁用Button的实现方案

解决方案:通过INotifyDataErrorInfo实现验证错误联动按钮禁用

你当前使用的ValidationRules属于视图层验证,默认情况下只有验证通过时才会更新绑定源,导致ViewModel无法感知错误状态。改用INotifyDataErrorInfo将验证逻辑移至ViewModel层,既能保留错误提示,又能统一管理所有Order的错误状态,进而实现按钮的禁用控制。

步骤1:让Order类实现INotifyDataErrorInfo

修改Order类,继承BindableBase的同时实现INotifyDataErrorInfo接口,将ID的验证逻辑内嵌到属性变更中,并维护错误状态:

public class Order : BindableBase, INotifyDataErrorInfo
{
    private int? _id;
    private readonly Dictionary<string, List<string>> _errors = new Dictionary<string, List<string>>();

    public int? ID
    {
        get => _id;
        set
        {
            if (SetProperty(ref _id, value))
            {
                ValidateID(value);
            }
        }
    }

    // 替换为你的实际验证规则
    private void ValidateID(int? value)
    {
        var propertyName = nameof(ID);
        _errors.Remove(propertyName);

        if (!value.HasValue)
        {
            AddError(propertyName, "ID不能为空");
        }
        else if (value < 1 || value > 100)
        {
            AddError(propertyName, "ID必须在1-100范围内");
        }

        OnErrorsChanged(propertyName);
    }

    private void AddError(string propertyName, string errorMessage)
    {
        if (!_errors.ContainsKey(propertyName))
        {
            _errors[propertyName] = new List<string>();
        }
        _errors[propertyName].Add(errorMessage);
    }

    public bool HasErrors => _errors.Any(kv => kv.Value.Any());

    public event EventHandler<DataErrorsChangedEventArgs>? ErrorsChanged;

    public IEnumerable GetErrors(string? propertyName)
    {
        if (string.IsNullOrEmpty(propertyName) || !_errors.ContainsKey(propertyName))
        {
            return Enumerable.Empty<string>();
        }
        return _errors[propertyName];
    }

    protected virtual void OnErrorsChanged(string propertyName)
    {
        ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
    }
}

步骤2:在ViewModel中跟踪错误状态并控制按钮

修改ViewModel,监听OrderCollection的集合变化以及每个Order的错误变更事件,实时更新按钮的启用状态:

public class YourViewModel : BindableBase
{
    private bool _isButtonEnabled = true;
    public ObservableCollection<Order> OrderCollection { get; } = new ObservableCollection<Order>();

    public bool IsButtonEnabled
    {
        get => _isButtonEnabled;
        set => SetProperty(ref _isButtonEnabled, value);
    }

    public YourViewModel()
    {
        OrderCollection.CollectionChanged += OrderCollection_CollectionChanged;
    }

    private void OrderCollection_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
        {
            foreach (Order order in e.NewItems)
            {
                order.ErrorsChanged += Order_ErrorsChanged;
            }
        }

        if (e.OldItems != null)
        {
            foreach (Order order in e.OldItems)
            {
                order.ErrorsChanged -= Order_ErrorsChanged;
            }
        }

        UpdateButtonEnabledState();
    }

    private void Order_ErrorsChanged(object? sender, DataErrorsChangedEventArgs e)
    {
        UpdateButtonEnabledState();
    }

    private void UpdateButtonEnabledState()
    {
        // 检查所有Order是否无错误
        IsButtonEnabled = OrderCollection.All(order => !order.HasErrors);
    }
}

步骤3:调整XAML绑定

移除原视图层的ValidationRules,开启ValidatesOnNotifyDataErrors(默认已开启,显式声明更清晰),并将按钮的IsEnabled绑定到ViewModel的对应属性:

<Grid>
    <ItemsControl x:Name="MyItemsControl"
                  ItemsSource="{Binding Path=OrderCollection}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBox x:Name="MyTextBox"
                         Text="{Binding Path=ID, Mode=TwoWay, ValidatesOnNotifyDataErrors=True, UpdateSourceTrigger=PropertyChanged}">
                </TextBox>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

    <Button x:Name="MyButton"
            IsEnabled="{Binding IsButtonEnabled}">
        提交
    </Button>
</Grid>

关键说明

  • UpdateSourceTrigger=PropertyChanged:设置为实时验证,输入内容变化时立即触发验证,若需要失去焦点时验证可改为LostFocus。
  • 错误提示:WPF会自动识别INotifyDataErrorInfo的错误状态,为TextBox显示默认的红色错误边框,无需额外配置。
  • 状态联动:ViewModel通过监听所有Order的错误变更,实时更新按钮启用状态,确保任意Order存在错误时按钮禁用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 12:25:19