触发相关 属性 的验证 (FluentValidation)
Trigger Validation of a related property (FluentValidation)
我在 class 中有两个相互依赖的属性:
public class SomeClass
{
public DateTime EarliestDeliveryDate { get; set; }
public DateTime LatestDeliveryDate { get; set; }
...
}
我将 FluentValidation 配置如下:
using FluentValidation;
...
public class SomeValidator : AbstractValidator<SomeClass>
{
public SomeValidator ()
{
RuleFor(x => x.EarliestDeliveryDate).Must((order, earliestDeliveryDate) => earliestDeliveryDate < order.LatestDeliveryDate)
.WithMessage("Earliest delivery date has to be before the latest delivery date.");
RuleFor(x => x.LatestDeliveryDate)
.Must((order, latestDeliveryDate) => latestDeliveryDate > order.EarliestDeliveryDate)
.WithMessage("Latest delivery date has to be after the earliest delivery date.");
...
}
}
每个 属性 的验证都按预期工作。但是,如果用户为两个属性输入了无效日期,然后更正其中一个输入字段(假设是 EarliestDeliveryDate),则另一个 属性(例如 LatestDeliveryDate)的错误消息仍然存在。
如果一个 属性 的值发生变化,如何触发所有依赖属性的验证?
DateTime
结构的默认值为 1 月 1 日 A.D。也许用户界面中的无效日期被回发,然后被忽略,因此使用 DateTime 的默认值。
要解决此问题,您需要通过在 属性 类型的名称后放置一个 ?
字符来使每个属性都可以为空:DateTime?
public class SomeClass
{
public DateTime? EarliestDeliveryDate { get; set; }
public DateTime? LatestDeliveryDate { get; set; }
...
}
那么无效日期将是 null
,更糟糕的情况。如果两个日期都包含 DateTime 对象,您只想比较两个日期:
// If both fields are required:
RuleFor(x => x.EarliestDeliveryDate)
.NotEmpty();
RuleFor(x => x.LatestDeliveryDate)
.NotEmpty();
When(order => order.EarliestDeliveryDate.HasValue && order.LatestDeliveryDate.HasValue, () =>
{
RuleFor(x => x.EarliestDeliveryDate)
.Must((order, earliestDeliveryDate) => earliestDeliveryDate < order.LatestDeliveryDate)
.WithMessage("Earliest delivery date has to be before the latest delivery date.");
RuleFor(x => x.LatestDeliveryDate)
.Must((order, latestDeliveryDate) => latestDeliveryDate > order.EarliestDeliveryDate)
.WithMessage("Latest delivery date has to be after the earliest delivery date.");
});
我的建议是让您建模 class 实现 INotifyPropertyChanged
接口,然后在所有相关属性的 Setter 中引发事件,如下所示:
public int LocationId
{
get => locationId;
set
{
locationId = value;
NotifyPropertyChanged(nameof(LocationId));
if (HazardId != default && MeasuredPersianDate != default)
{
NotifyPropertyChanged(nameof(HazardId));
NotifyPropertyChanged(nameof(MeasuredPersianDate));
}
}
}
这样,如果你的 UI 是像 WPF 或 Xamarin Forms 这样的框架,当其中一个相关属性发生变化时,其他属性也会被触发验证 automatically.However,如果当 NotifyPropertyChanged
出现时,您的 UI 框架不会自动刷新视图,您需要订阅该事件并让 UI 触发相关 properties.For 的验证在 Blazor 中的示例,您可以使用以下代码:
model.PropertyChanged +=
(object sender, System.ComponentModel.PropertyChangedEventArgs e) =>
{
if (e.PropertyName is null) return;
form.EditContext!.NotifyFieldChanged(form.EditContext.Field(e.PropertyName));
};
其中 form
是使用 @ref
引用 EditForm 的变量
<EditForm @ref="form" Context="ctx" Model="model"OnValidSubmit="SaveChanges">...</EditForm>
我在 class 中有两个相互依赖的属性:
public class SomeClass
{
public DateTime EarliestDeliveryDate { get; set; }
public DateTime LatestDeliveryDate { get; set; }
...
}
我将 FluentValidation 配置如下:
using FluentValidation;
...
public class SomeValidator : AbstractValidator<SomeClass>
{
public SomeValidator ()
{
RuleFor(x => x.EarliestDeliveryDate).Must((order, earliestDeliveryDate) => earliestDeliveryDate < order.LatestDeliveryDate)
.WithMessage("Earliest delivery date has to be before the latest delivery date.");
RuleFor(x => x.LatestDeliveryDate)
.Must((order, latestDeliveryDate) => latestDeliveryDate > order.EarliestDeliveryDate)
.WithMessage("Latest delivery date has to be after the earliest delivery date.");
...
}
}
每个 属性 的验证都按预期工作。但是,如果用户为两个属性输入了无效日期,然后更正其中一个输入字段(假设是 EarliestDeliveryDate),则另一个 属性(例如 LatestDeliveryDate)的错误消息仍然存在。
如果一个 属性 的值发生变化,如何触发所有依赖属性的验证?
DateTime
结构的默认值为 1 月 1 日 A.D。也许用户界面中的无效日期被回发,然后被忽略,因此使用 DateTime 的默认值。
要解决此问题,您需要通过在 属性 类型的名称后放置一个 ?
字符来使每个属性都可以为空:DateTime?
public class SomeClass
{
public DateTime? EarliestDeliveryDate { get; set; }
public DateTime? LatestDeliveryDate { get; set; }
...
}
那么无效日期将是 null
,更糟糕的情况。如果两个日期都包含 DateTime 对象,您只想比较两个日期:
// If both fields are required:
RuleFor(x => x.EarliestDeliveryDate)
.NotEmpty();
RuleFor(x => x.LatestDeliveryDate)
.NotEmpty();
When(order => order.EarliestDeliveryDate.HasValue && order.LatestDeliveryDate.HasValue, () =>
{
RuleFor(x => x.EarliestDeliveryDate)
.Must((order, earliestDeliveryDate) => earliestDeliveryDate < order.LatestDeliveryDate)
.WithMessage("Earliest delivery date has to be before the latest delivery date.");
RuleFor(x => x.LatestDeliveryDate)
.Must((order, latestDeliveryDate) => latestDeliveryDate > order.EarliestDeliveryDate)
.WithMessage("Latest delivery date has to be after the earliest delivery date.");
});
我的建议是让您建模 class 实现 INotifyPropertyChanged
接口,然后在所有相关属性的 Setter 中引发事件,如下所示:
public int LocationId
{
get => locationId;
set
{
locationId = value;
NotifyPropertyChanged(nameof(LocationId));
if (HazardId != default && MeasuredPersianDate != default)
{
NotifyPropertyChanged(nameof(HazardId));
NotifyPropertyChanged(nameof(MeasuredPersianDate));
}
}
}
这样,如果你的 UI 是像 WPF 或 Xamarin Forms 这样的框架,当其中一个相关属性发生变化时,其他属性也会被触发验证 automatically.However,如果当 NotifyPropertyChanged
出现时,您的 UI 框架不会自动刷新视图,您需要订阅该事件并让 UI 触发相关 properties.For 的验证在 Blazor 中的示例,您可以使用以下代码:
model.PropertyChanged +=
(object sender, System.ComponentModel.PropertyChangedEventArgs e) =>
{
if (e.PropertyName is null) return;
form.EditContext!.NotifyFieldChanged(form.EditContext.Field(e.PropertyName));
};
其中 form
是使用 @ref
<EditForm @ref="form" Context="ctx" Model="model"OnValidSubmit="SaveChanges">...</EditForm>