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

Xceed PropertyGrid属性验证设置及UI提示异常问题咨询

WPF Extended Toolkit PropertyGrid 验证问题解决方案

问题1:Range特性无UI错误提示

问题描述

使用[Range]数据注解特性限制Age属性范围(0-150),虽然能阻止非法输入,但UI上没有红框标记或错误提示,调试发现IDataErrorInfo的索引器未被调用。

Person类代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.CompilerServices;

namespace WpfApp1
{
    public class Person: INotifyPropertyChanged, IDataErrorInfo
    {
        [Required(ErrorMessage = "Name is Required")]
        [DisplayName("Name")]
        public string Name { set; get; }

        [Range(0,150,ErrorMessage = "Age= 0~150")]
        [DisplayName("Age")]
        public int Age { set; get; }

        public event PropertyChangedEventHandler? PropertyChanged;

        [Browsable(false)]
        public string Error { get; }

        public string this[string propertyName]
        {
            get
            {
                if (string.IsNullOrEmpty(propertyName))
                {
                    throw new ArgumentException("Invalid property name", propertyName);
                }
                string error = string.Empty;
                var val = GetType().GetProperty(propertyName).GetValue(this, null);
            
                var results = new List<System.ComponentModel.DataAnnotations.ValidationResult>(1);
                var result = Validator.TryValidateProperty(val, new ValidationContext(this, null, null)
                    { MemberName = propertyName }, results);
                if (!result)
                {
                    var validationResult = results.First();
                    error = validationResult.ErrorMessage;
                }
                
                return error;
            }
        }

        protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) => this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));

        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
        {
            PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
            propertyChanged?.Invoke(this, args);
        }
    }
}

XAML及后台代码

<xctk:PropertyGrid Name="XctkPropertyGrid" Loaded="PropertyGrid_Loaded"></xctk:PropertyGrid>
private void PropertyGrid_Loaded(object sender, RoutedEventArgs e)
{
    Person p = new Person(){Age = 20,Name = "wala"};
    this.XctkPropertyGrid.SelectedObject = p;
}

原因分析

  1. 自动属性未触发PropertyChanged:Name和Age是自动属性,setter中没有调用RaisePropertyChanged,PropertyGrid无法感知属性值变化,不会触发IDataErrorInfo验证。
  2. PropertyGrid未启用验证显示:默认情况下,PropertyGrid未开启错误提示的UI显示开关。

解决方案

  1. 修改自动属性为带通知的属性:将自动属性改为手动实现,在setter中触发PropertyChanged事件,确保属性变更被PropertyGrid捕获。
  2. 启用PropertyGrid的验证显示:在XAML中设置ShowValidationErrors="True",开启错误提示UI。

修改后的Person类关键代码:

private string _name;
[Required(ErrorMessage = "Name is Required")]
[DisplayName("Name")]
public string Name 
{ 
    get => _name;
    set 
    {
        _name = value;
        RaisePropertyChanged();
    }
}

private int _age;
[Range(0,150,ErrorMessage = "Age= 0~150")]
[DisplayName("Age")]
public int Age 
{ 
    get => _age;
    set 
    {
        _age = value;
        RaisePropertyChanged();
    }
}

修改后的XAML:

<xctk:PropertyGrid Name="XctkPropertyGrid" Loaded="PropertyGrid_Loaded" ShowValidationErrors="True"></xctk:PropertyGrid>

问题2:错误红框无法消失

问题描述

改用Person2类后,输入非法值时会显示红框提示,但离开输入框后,值恢复为合法值,红框却持续存在。

Person2类代码

public class Person2 : INotifyPropertyChanged, IDataErrorInfo
{
    [DisplayName("Name")]
    public string Name { set; get; }

    private int _age;
    [DisplayName("Age")]
    public int Age {
        set
        {
            if (!ValidataProperty(nameof(Age), value))
                return;
            _age = value;
            RaisePropertyChanged(nameof(Age));
        }
        get
        {
            return _age;
        }
    }

    public event PropertyChangedEventHandler? PropertyChanged;

    [Browsable(false)]
    public string Error { get; }

    protected bool ValidataProperty(string propertyName, object val)
    {
        if (propertyName.Equals(nameof(Age)))
        {
            int ageVal = (int)val;
            if (ageVal < 0 || ageVal > 150)
            {
                ErrorProperty = propertyName;
                ErrorMsg = "Age =0~150";
                return false;
            }
        }

        ErrorMsg = string.Empty;
        ErrorProperty = string.Empty;
        return true;
    }

    private string ErrorProperty;
    private string ErrorMsg;

    public string this[string propertyName]
    {
        get
        {
            if (ErrorProperty.Equals(propertyName))
            {
                return ErrorMsg;
            }
            return string.Empty;
        }
    }

    protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) => this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
    {
        PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        propertyChanged?.Invoke(this, args);
    }
}

原因分析

当输入非法值时,ValidataProperty方法设置了ErrorProperty和ErrorMsg,但此时属性值并未更新。当用户离开输入框,控件自动恢复为之前的合法值,但此时没有触发验证状态的重置,IDataErrorInfo索引器仍然返回错误信息,导致红框不消失。

解决方案

  1. 在验证失败时触发属性变更通知:即使属性值未更新,也需要调用RaisePropertyChanged,让PropertyGrid重新验证该属性。
  2. 重置错误状态时触发验证更新:确保在验证通过或需要清空错误时,通知PropertyGrid重新获取错误信息。

修改后的Person2类关键代码:

protected bool ValidataProperty(string propertyName, object val)
{
    if (propertyName.Equals(nameof(Age)))
    {
        int ageVal = (int)val;
        if (ageVal < 0 || ageVal > 150)
        {
            ErrorProperty = propertyName;
            ErrorMsg = "Age =0~150";
            // 触发属性变更,让PropertyGrid重新验证
            RaisePropertyChanged(propertyName);
            return false;
        }
    }

    ErrorMsg = string.Empty;
    ErrorProperty = string.Empty;
    // 清空错误后触发验证更新
    RaisePropertyChanged(propertyName);
    return true;
}

另外,将Name属性也改为带通知的实现,保持一致性:

private string _name;
[DisplayName("Name")]
public string Name 
{ 
    get => _name;
    set 
    {
        _name = value;
        RaisePropertyChanged();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 03:43:21