Files
qhmes/yy-admin-master/YY.Admin.Core/FluentValidation/FluentAutoValidationRule.cs

83 lines
3.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using FluentValidation;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using ValidationResult = System.Windows.Controls.ValidationResult;
namespace YY.Admin.Core.FluentValidation
{
internal class FluentAutoValidationRule<T> : ValidationRule, IFluentAutoValidationRule where T : class
{
public IValidator<T>? Validator { get; set; }
/// <summary>
/// 当前绑定控件对应的属性名
/// </summary>
public string? PropertyName { get; set; }
// 👇 ValidationStep.UpdatedValue为true: 让Validate方法中value参数为BindingExpression类型而非值类型
public FluentAutoValidationRule() : base(ValidationStep.UpdatedValue, true) { }
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (Validator == null || string.IsNullOrEmpty(PropertyName))
return ValidationResult.ValidResult;
// 如果 value 不是 BindingExpression先尝试判断是否是 BindingGroup (兼容性保护)
if (value is not BindingExpression bindingExpr)
{
// 有时 WPF 在不同阶段会传入 BindingGroup 或其他类型,直接跳过初始化阶段的验证,避免误报
return ValidationResult.ValidResult;
}
// --- 更可靠地判断“初始化阶段的第一次验证” ---
// 如果绑定目标尚未挂到视觉树或控件未 Loaded则视为初始化不执行验证
var target = bindingExpr.Target as DependencyObject;
if (target != null)
{
// 1) 如果是 FrameworkElement 并且还没 Loaded则跳过
if (target is FrameworkElement fe && !fe.IsLoaded)
return ValidationResult.ValidResult;
// 2) 如果 PresentationSource 为空,也说明还没连接到可视树,跳过
var ps = System.Windows.PresentationSource.FromVisual(target as System.Windows.Media.Visual);
if (ps == null)
return ValidationResult.ValidResult;
// 3) 另外,如果控件不可见,也可能是初始化阶段,可根据需要跳过
if (target is UIElement ui && !ui.IsVisible)
return ValidationResult.ValidResult;
}
var dataItem = bindingExpr.DataItem;
if (dataItem == null)
return new ValidationResult(false, "绑定源为空");
// 解析 Path例如 "SysUser.Account"
var path = bindingExpr.ParentBinding.Path?.Path ?? string.Empty;
var rootPropName = path.Split('.')[0]; // SysUser
var modelProp = dataItem.GetType().GetProperty(rootPropName);
if (modelProp == null)
return ValidationResult.ValidResult;
var modelObj = modelProp.GetValue(dataItem);
if (modelObj is not T model)
return ValidationResult.ValidResult;
// 调用 FluentValidation 验证指定属性
var result = Validator.ValidateAsync(model, opts => opts.IncludeProperties(PropertyName))
.ConfigureAwait(false) // 同步等待TaskValidationRule 不支持 async → 只能同步等待。)
.GetAwaiter()
.GetResult();
var error = result.Errors.FirstOrDefault(e => e.PropertyName == PropertyName);
if (error != null)
return new ValidationResult(false, error.ErrorMessage);
return ValidationResult.ValidResult;
}
}
}