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

83 lines
3.6 KiB
C#
Raw Normal View History

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;
}
}
}