.NET MAUI中ObservableValidator调用GetErrors()触发异常
.NET MAUI ObservableValidator 验证异常解决方案
问题根源
异常触发点在k.MemberNames.First(),原因是自定义GreaterThanAttribute返回错误时,未指定关联的属性名,导致MemberNames为空集合,调用First()直接抛出"Sequence has no Elements"异常;同时索引器逻辑未处理空MemberNames的边界情况。
修复步骤
1. 修正自定义验证属性的错误返回逻辑
在GreaterThanAttribute中,返回错误时必须指定当前验证的属性名到MemberNames,同时增加空值判断避免额外报错:
public sealed class GreaterThanAttribute : ValidationAttribute { public GreaterThanAttribute(string propertyName) { PropertyName = propertyName; } public string PropertyName { get; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { object instance = validationContext.ObjectInstance; var otherProperty = instance.GetType().GetProperty(PropertyName); // 检查对比属性是否存在 if (otherProperty == null) { return new ValidationResult($"Property {PropertyName} not found", new[] { validationContext.MemberName }); } object otherValue = otherProperty.GetValue(instance); // 处理空值,避免强制转换IComparable报错 if (value == null || otherValue == null) { return new ValidationResult("Value cannot be null", new[] { validationContext.MemberName }); } if (((IComparable)value).CompareTo(otherValue) > 0) { return ValidationResult.Success; } // 指定当前验证的属性名到MemberNames return new ValidationResult("out of specification", new[] { validationContext.MemberName }); } }
2. 修复索引器的错误处理逻辑
在获取错误字典时,先过滤掉无MemberNames的错误,避免调用First()报错:
[IndexerName("Item")] public ValidationStatus this[string propertyName] { get { var errors = this.GetErrors() .Where(error => error.MemberNames.Any()) // 过滤无效错误项 .ToDictionary(error => error.MemberNames.First(), error => error.ErrorMessage) ?? new Dictionary<string, string?>(); var hasErrors = errors.TryGetValue(propertyName, out var error); return new ValidationStatus(hasErrors, error ?? string.Empty); } }
3. 优化ViewModel属性设置逻辑
ObservableValidator的SetProperty方法已内置验证触发逻辑,无需手动调用ClearErrors和ValidateAllProperties,简化代码:
[GreaterThan(nameof(StaticPressSpec))] public double? StaticPressResult { get => this.staticPressResult; set { if (SetProperty(ref this.staticPressResult, value, true)) { OnPropertyChanged("Item[StaticPressResult]"); } } }
额外注意事项
- 确保
StaticPressSpec有有效值:若该属性未初始化,验证时会触发空值错误,建议设置默认值或加入必填验证。 - 保留XAML绑定逻辑不变:原有的
[StaticPressResult].HasError绑定可正常工作。
内容的提问来源于stack exchange,提问作者scott
相关产品推荐
相关产品推荐

