如何在我的 xamarin.forms 应用程序中使用 FluentValidation 将错误消息分配给良好的文本标签
How to assign an error message to the good text label with FluentValidaiton in my xamarin.forms app
用户当前正在填写一个有多个条目的表单。现在我在每个条目下都有一个标签,如果验证没有通过,它将显示错误消息。
我的问题是现在无法将正确的错误消息分配给正确的标签。因为如果一个错误发生而另一个错误没有发生,我会得到一个错误,即索引不存在,这会导致错误。
可能吗?注意:这是我第一次使用 Fluent Validation,实现可能不太好。所以请随时提出更好的实施方案
我自己创建了一个验证器 class,其中包含我在 UI 中绑定的 属性。这些将用于显示错误消息。 (请注意,它们也已在 BaseViewModel.cs 中定义)
public class Validator
{
public string TasksGroupDescriptionWarning { get; set; }
public string TasksGroupDateWarning { get; set; }
}
我的两个条目,它们的标签分配给了属性
<StackLayout >
<Label Text="Date de calcul:" FontAttributes="Bold" FontFamily="ROBOTO" TextColor="#000000"></Label>
<DatePicker Date="{Binding TasksGroupDate}" FontFamily="ROBOTO" Format="yyyy-MM-dd" ></DatePicker>
<Label Text="{Binding TasksGroupDateWarning}" TextColor="#FF0000" FontAttributes="Bold"></Label>
</StackLayout>
<StackLayout >
<Label Text="Description de la journée" FontAttributes="Bold" FontFamily="ROBOTO" TextColor="#000000"></Label>
<Entry x:Name="TasksGroupDescription" Text="{Binding TasksGroupDescription}"/>
<Label Text="{Binding TasksGroupDescriptionWarning}" TextColor="#FF0000" FontAttributes="Bold"></Label>
</StackLayout>
My TasksGroupValidator.cs 验证 TasksGroup 对象。
public class TasksGroupValidator : AbstractValidator<TasksGroup>
{
public TasksGroupValidator()
{
RuleFor(p => p.TasksGroupDescription).NotEmpty().WithMessage("* Veuillez entrer une description.");
RuleFor(p => p.TasksGroupDate).Must(BeValidDate).WithMessage("* Vous ne pouvez pas entrer une date supérieure à celle d'aujourd'hui.");
}
protected bool BeValidDate(DateTime date)
{
DateTime currentDate = DateTime.Now;
if (date > currentDate)
{
return false;
}
return true;
}
}
这是我保存表单和验证的地方,如果我同时有两个错误,它会起作用,但如果我只有两个错误之一,我会得到一个索引第二个错误,因为它不存在
async Task SaveNewTask()
{
// in my code i created a TasksGroup object
TasksGroupValidator tasksGroupValidator = new TasksGroupValidator();
ValidationResult results = tasksGroupValidator.Validate(tasksGroup);
if (results.IsValid == false)
{
//assign to first label
TasksGroupDescriptionWarning = results.Errors[0].ErrorMessage;
validator.TasksGroupDescriptionWarning = TasksGroupDescriptionWarning;
//assign to second label
TasksGroupDateWarning = results.Errors[1].ErrorMessage;
validator.TasksGroupDateWarning = TasksGroupDateWarning;
}
//else save to database
}
编辑以在评论中获得答案
public bool Validate(TasksGroup tasksGroup)
{
ValidationResult results = validator.Validate(tasksGroup);
if (!results.IsValid)
{
foreach (var e in results.Errors)
{
ErrorMessages[e.PropertyName] = e.ErrorMessage;
}
}
NotifyPropertyChanged(nameof(ErrorMessages));
return results.IsValid;
}
async Task SaveNewTask()
{
IsBusy = true;
await Task.Delay(4000);
IsBusy = false;
TasksGroup tasksGroup = new TasksGroup();
Tasks tasks = new Tasks();
tasksGroup.TasksGroupDescription = TasksGroupDescription;
tasksGroup.TasksGroupDate = TasksGroupDate;
tasks.TaskDuration = TaskDuration;
tasks.TaskDBA = TaskDBA;
tasks.TaskDescription = TaskDescription;
tasksGroup.Taches = new List<Tasks>() { tasks };
if(Validate(tasksGroup))
{
await App.Database.SaveTasksGroupAsync(tasksGroup);
await Application.Current.MainPage.DisplayAlert("Save", "La tâche a été enregistrée", "OK");
await Application.Current.MainPage.Navigation.PopAsync();
NotifyPropertyChanged();
}
您可以使用 Dictionary
来存储验证消息。
这是一个代码片段,您可以根据自己的代码进行调整。
视图模型:
public class TaskGroupViewModel : INotifyPropertyChanged
{
public TaskGroup TaskGroup { get; set; }
public IDictionary<string, string> ErrorMessages { get; set; }
public ICommand ValidateCommand { get; }
private readonly AbstractValidator<TaskGroup> _validator;
public TaskGroupViewModel()
{
TaskGroup = new TaskGroup();
ErrorMessages = new Dictionary<string, string>();
ValidateCommand = new Command(() => Validate());
_validator = new InlineValidator<TaskGroup>();
_validator.RuleFor(x => x.TasksGroupDate)
.Must(x => x > DateTime.Now)
.WithMessage("* Vous ne pouvez pas entrer une date supérieure à celle d'aujourd'hui.");
_validator.RuleFor(x => x.TasksGroupDescription)
.NotEmpty()
.WithMessage("* Veuillez entrer une description.");
}
public bool Validate()
{
ErrorMessages.Clear();
var result = _validator.Validate(TaskGroup);
if (!result.IsValid)
{
foreach (var e in result.Errors)
{
ErrorMessages[e.PropertyName] = e.ErrorMessage;
}
}
OnPropertyChanged(nameof(ErrorMessages));
return result.IsValid;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML:
....
<StackLayout>
<StackLayout >
<Label Text="Date de calcul:" FontAttributes="Bold" FontFamily="ROBOTO" TextColor="#000000"></Label>
<DatePicker Date="{Binding TaskGroup.TasksGroupDate}" FontFamily="ROBOTO" Format="yyyy-MM-dd" ></DatePicker>
<Label Text="{Binding ErrorMessages[TasksGroupDate]}" TextColor="#FF0000" FontAttributes="Bold"></Label>
</StackLayout>
<StackLayout >
<Label Text="Description de la journée" FontAttributes="Bold" FontFamily="ROBOTO" TextColor="#000000"></Label>
<Entry x:Name="TasksGroupDescription" Text="{Binding TaskGroup.TasksGroupDescription}"/>
<Label Text="{Binding ErrorMessages[TasksGroupDescription]}" TextColor="#FF0000" FontAttributes="Bold"></Label>
</StackLayout>
<Button Text="Validate" Command="{Binding ValidateCommand, Mode=OneTime}"/>
</StackLayout>
...
用户当前正在填写一个有多个条目的表单。现在我在每个条目下都有一个标签,如果验证没有通过,它将显示错误消息。
我的问题是现在无法将正确的错误消息分配给正确的标签。因为如果一个错误发生而另一个错误没有发生,我会得到一个错误,即索引不存在,这会导致错误。
可能吗?注意:这是我第一次使用 Fluent Validation,实现可能不太好。所以请随时提出更好的实施方案
我自己创建了一个验证器 class,其中包含我在 UI 中绑定的 属性。这些将用于显示错误消息。 (请注意,它们也已在 BaseViewModel.cs 中定义)
public class Validator
{
public string TasksGroupDescriptionWarning { get; set; }
public string TasksGroupDateWarning { get; set; }
}
我的两个条目,它们的标签分配给了属性
<StackLayout >
<Label Text="Date de calcul:" FontAttributes="Bold" FontFamily="ROBOTO" TextColor="#000000"></Label>
<DatePicker Date="{Binding TasksGroupDate}" FontFamily="ROBOTO" Format="yyyy-MM-dd" ></DatePicker>
<Label Text="{Binding TasksGroupDateWarning}" TextColor="#FF0000" FontAttributes="Bold"></Label>
</StackLayout>
<StackLayout >
<Label Text="Description de la journée" FontAttributes="Bold" FontFamily="ROBOTO" TextColor="#000000"></Label>
<Entry x:Name="TasksGroupDescription" Text="{Binding TasksGroupDescription}"/>
<Label Text="{Binding TasksGroupDescriptionWarning}" TextColor="#FF0000" FontAttributes="Bold"></Label>
</StackLayout>
My TasksGroupValidator.cs 验证 TasksGroup 对象。
public class TasksGroupValidator : AbstractValidator<TasksGroup>
{
public TasksGroupValidator()
{
RuleFor(p => p.TasksGroupDescription).NotEmpty().WithMessage("* Veuillez entrer une description.");
RuleFor(p => p.TasksGroupDate).Must(BeValidDate).WithMessage("* Vous ne pouvez pas entrer une date supérieure à celle d'aujourd'hui.");
}
protected bool BeValidDate(DateTime date)
{
DateTime currentDate = DateTime.Now;
if (date > currentDate)
{
return false;
}
return true;
}
}
这是我保存表单和验证的地方,如果我同时有两个错误,它会起作用,但如果我只有两个错误之一,我会得到一个索引第二个错误,因为它不存在
async Task SaveNewTask()
{
// in my code i created a TasksGroup object
TasksGroupValidator tasksGroupValidator = new TasksGroupValidator();
ValidationResult results = tasksGroupValidator.Validate(tasksGroup);
if (results.IsValid == false)
{
//assign to first label
TasksGroupDescriptionWarning = results.Errors[0].ErrorMessage;
validator.TasksGroupDescriptionWarning = TasksGroupDescriptionWarning;
//assign to second label
TasksGroupDateWarning = results.Errors[1].ErrorMessage;
validator.TasksGroupDateWarning = TasksGroupDateWarning;
}
//else save to database
}
编辑以在评论中获得答案
public bool Validate(TasksGroup tasksGroup)
{
ValidationResult results = validator.Validate(tasksGroup);
if (!results.IsValid)
{
foreach (var e in results.Errors)
{
ErrorMessages[e.PropertyName] = e.ErrorMessage;
}
}
NotifyPropertyChanged(nameof(ErrorMessages));
return results.IsValid;
}
async Task SaveNewTask()
{
IsBusy = true;
await Task.Delay(4000);
IsBusy = false;
TasksGroup tasksGroup = new TasksGroup();
Tasks tasks = new Tasks();
tasksGroup.TasksGroupDescription = TasksGroupDescription;
tasksGroup.TasksGroupDate = TasksGroupDate;
tasks.TaskDuration = TaskDuration;
tasks.TaskDBA = TaskDBA;
tasks.TaskDescription = TaskDescription;
tasksGroup.Taches = new List<Tasks>() { tasks };
if(Validate(tasksGroup))
{
await App.Database.SaveTasksGroupAsync(tasksGroup);
await Application.Current.MainPage.DisplayAlert("Save", "La tâche a été enregistrée", "OK");
await Application.Current.MainPage.Navigation.PopAsync();
NotifyPropertyChanged();
}
您可以使用 Dictionary
来存储验证消息。
这是一个代码片段,您可以根据自己的代码进行调整。
视图模型:
public class TaskGroupViewModel : INotifyPropertyChanged
{
public TaskGroup TaskGroup { get; set; }
public IDictionary<string, string> ErrorMessages { get; set; }
public ICommand ValidateCommand { get; }
private readonly AbstractValidator<TaskGroup> _validator;
public TaskGroupViewModel()
{
TaskGroup = new TaskGroup();
ErrorMessages = new Dictionary<string, string>();
ValidateCommand = new Command(() => Validate());
_validator = new InlineValidator<TaskGroup>();
_validator.RuleFor(x => x.TasksGroupDate)
.Must(x => x > DateTime.Now)
.WithMessage("* Vous ne pouvez pas entrer une date supérieure à celle d'aujourd'hui.");
_validator.RuleFor(x => x.TasksGroupDescription)
.NotEmpty()
.WithMessage("* Veuillez entrer une description.");
}
public bool Validate()
{
ErrorMessages.Clear();
var result = _validator.Validate(TaskGroup);
if (!result.IsValid)
{
foreach (var e in result.Errors)
{
ErrorMessages[e.PropertyName] = e.ErrorMessage;
}
}
OnPropertyChanged(nameof(ErrorMessages));
return result.IsValid;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML:
....
<StackLayout>
<StackLayout >
<Label Text="Date de calcul:" FontAttributes="Bold" FontFamily="ROBOTO" TextColor="#000000"></Label>
<DatePicker Date="{Binding TaskGroup.TasksGroupDate}" FontFamily="ROBOTO" Format="yyyy-MM-dd" ></DatePicker>
<Label Text="{Binding ErrorMessages[TasksGroupDate]}" TextColor="#FF0000" FontAttributes="Bold"></Label>
</StackLayout>
<StackLayout >
<Label Text="Description de la journée" FontAttributes="Bold" FontFamily="ROBOTO" TextColor="#000000"></Label>
<Entry x:Name="TasksGroupDescription" Text="{Binding TaskGroup.TasksGroupDescription}"/>
<Label Text="{Binding ErrorMessages[TasksGroupDescription]}" TextColor="#FF0000" FontAttributes="Bold"></Label>
</StackLayout>
<Button Text="Validate" Command="{Binding ValidateCommand, Mode=OneTime}"/>
</StackLayout>
...