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; }
原因分析
- 自动属性未触发PropertyChanged:
Name和Age是自动属性,setter中没有调用RaisePropertyChanged,PropertyGrid无法感知属性值变化,不会触发IDataErrorInfo验证。 - PropertyGrid未启用验证显示:默认情况下,PropertyGrid未开启错误提示的UI显示开关。
解决方案
- 修改自动属性为带通知的属性:将自动属性改为手动实现,在setter中触发
PropertyChanged事件,确保属性变更被PropertyGrid捕获。 - 启用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索引器仍然返回错误信息,导致红框不消失。
解决方案
- 在验证失败时触发属性变更通知:即使属性值未更新,也需要调用
RaisePropertyChanged,让PropertyGrid重新验证该属性。 - 重置错误状态时触发验证更新:确保在验证通过或需要清空错误时,通知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
相关产品推荐
相关产品推荐

