英文:
Issues with .NET MAUI Blazor app, MudBlazor, and FluentValidation in a MudForm
问题
我目前正在开发我的第一个.NET MAUI Blazor应用程序,并使用MudBlazor用于UI组件。我正在尝试使用<MudForm>
创建一个表单,该表单使用NewReservationViewModel
,并希望使用FluentValidation进行验证。
以下是我的表单代码:
<MudForm Model="@ViewModel" Validation="???">
<MudSelect Label="Building" @bind-Value="@ViewModel.BuildingId" T="int?" Disabled="@IsFloorListDisabled" Required="true" ValueChanged="OnBuildingSelectionChanged">
<MudSelectItem T="int?" Value="null">Select Building</MudSelectItem>
@if (ViewModel.Buildings != null && ViewModel.Buildings.Count > 0)
{
@foreach (var building in ViewModel.Buildings)
{
<MudSelectItem T="int?" Value="@building.Id">@building.Name</MudSelectItem>
}
}
</MudSelect>
<MudSelect Label="Floor" @bind-Value="@ViewModel.FloorId" T="int?" Disabled="@IsFloorListDisabled" Required="true">
<MudSelectItem T="int?" Value="null">Select Floor</MudSelectItem>
@if (ViewModel.Floors != null && ViewModel.Floors.Count > 0)
{
@foreach (var floor in ViewModel.Floors)
{
<MudSelectItem T="int?" Value="@floor.Id">@floor.Name</MudSelectItem>
}
}
</MudSelect>
<MudDatePicker Label="Start Date" @bind-Date="@ViewModel.Start" Required="true"></MudDatePicker>
<MudDatePicker Label="Finish Date" @bind-Date="@ViewModel.Finish" Required="true"></MudDatePicker>
<MudButton Color="Color.Primary" Variant="Variant.Filled" Type="ButtonType.Submit">Search</MudButton>
</MudForm>
这是NewReservationViewModel
:
public class NewReservationViewModel
{
public int Id { get; set; }
public DateTime? Start { get; set; }
public DateTime? Finish { get; set; }
public int? BuildingId { get; set; }
public List<BuildingDto> Buildings { get; set; }
public int? FloorId { get; set; }
public List<FloorDto> Floors { get; set; }
public string AreaTypes { get; set; }
}
我还为NewReservationViewModel
实现了验证器:
public class NewReservationViewModelValidation : AbstractValidator<NewReservationViewModel>
{
public NewReservationViewModelValidation()
{
RuleFor(model => model.Start).NotEmpty().WithMessage("bla bla bla");
RuleFor(model => model.Finish).NotEmpty().WithMessage("bla bla bla")
.GreaterThan(model => model.Start).WithMessage("bla bla bla");
RuleFor(model => model.BuildingId).NotEmpty().WithMessage("bla bla bla");
RuleFor(model => model.FloorId).NotEmpty().WithMessage("bla bla bla");
}
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
{
try
{
var result = await ValidateAsync(ValidationContext<NewReservationViewModel>
.CreateWithOptions((NewReservationViewModel)model, x => x.IncludeProperties(propertyName)));
if (result.IsValid)
return Array.Empty<string>();
return result.Errors.Select(e => e.ErrorMessage);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
};
}
问题:
- 为什么我无法同时使用
ValueChanged="OnBuildingSelectionChanged"
和@bind-Value="@ViewModel.BuildingId"
?我需要知道何时选择了一个值,以调用OnBuildingSelectionChanged
方法,在选择建筑物时填充楼层列表(级联下拉列表)。 - 如果存在任何表单错误,如何显示这些错误?
任何关于这些问题的帮助或见解将不胜感激。谢谢!
英文:
Description:
I'm currently working on my first .NET MAUI Blazor app and using MudBlazor for UI components. I'm trying to create a form using <MudForm>
with the NewReservationViewModel
, and I want to handle validation using FluentValidation.
Here's my form code:
<MudForm Model="@ViewModel" Validation="???">
<MudSelect Label="Building" @bind-Value="@ViewModel.BuildingId" T="int?" Disabled="@IsFloorListDisabled" Required="true" ValueChanged="OnBuildingSelectionChanged">
<MudSelectItem T="int?" Value="null">Select Building</MudSelectItem>
@if (ViewModel.Buildings != null && ViewModel.Buildings.Count > 0)
{
@foreach (var building in ViewModel.Buildings)
{
<MudSelectItem T="int?" Value="@building.Id">@building.Name</MudSelectItem>
}
}
</MudSelect>
<MudSelect Label="Floor" @bind-Value="@ViewModel.FloorId" T="int?" Disabled="@IsFloorListDisabled" Required="true">
<MudSelectItem T="int?" Value="null">Select Floor</MudSelectItem>
@if (ViewModel.Floors != null && ViewModel.Floors.Count > 0)
{
@foreach (var floor in ViewModel.Floors)
{
<MudSelectItem T="int?" Value="@floor.Id">@floor.Name</MudSelectItem>
}
}
</MudSelect>
<MudDatePicker Label="Start Date" @bind-Date="@ViewModel.Start" Required="true"></MudDatePicker>
<MudDatePicker Label="Finish Date" @bind-Date="@ViewModel.Finish" Required="true"></MudDatePicker>
<MudButton Color="Color.Primary" Variant="Variant.Filled" Type="ButtonType.Submit">Search</MudButton>
</MudForm>
And here's the NewReservationViewModel
:
public class NewReservationViewModel
{
public int Id { get; set; }
public DateTime? Start { get; set; }
public DateTime? Finish { get; set; }
public int? BuildingId { get; set; }
public List<BuildingDto> Buildings { get; set; }
public int? FloorId { get; set; }
public List<FloorDto> Floors { get; set; }
public string AreaTypes { get; set; }
}
I've also implemented a validator for the NewReservationViewModel
:
public class NewReservationViewModelValidation : AbstractValidator<NewReservationViewModel>
{
public NewReservationViewModelValidation()
{
RuleFor(model => model.Start).NotEmpty().WithMessage("bla bla bla");
RuleFor(model => model.Finish).NotEmpty().WithMessage("bla bla bla")
.GreaterThan(model => model.Start).WithMessage("bla bla bla");
RuleFor(model => model.BuildingId).NotEmpty().WithMessage("bla bla bla");
RuleFor(model => model.FloorId).NotEmpty().WithMessage("bla bla bla");
}
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
{
try
{
var result = await ValidateAsync(ValidationContext<NewReservationViewModel>
.CreateWithOptions((NewReservationViewModel)model, x => x.IncludeProperties(propertyName)));
if (result.IsValid)
return Array.Empty<string>();
return result.Errors.Select(e => e.ErrorMessage);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
};
}
Questions:
Why am I unable to use ValueChanged="OnBuildingSelectionChanged"
together with @bind-Value="@ViewModel.BuildingId"
? I need know when a value is selected, to call the OnBuildingSelectionChanged
method to populate the list of floors when a building is selected (Cascading drop down lists).
How can I display the form errors if there are any?
Any help or insights into these issues would be greatly appreciated. Thank you!
答案1
得分: 2
>为什么我无法同时使用ValueChanged="OnBuildingSelectionChanged"
和@bind-Value="@ViewModel.BuildingId"
?
@bind-Value
实际上是使用Value
和ValueChanged
的简写方式。MS Docs。
<SomeComponent Value="_myValue" ValueChanged="HandleValueChanged"/>
<SomeComponent @bind-Value="_myValue"/>
当您使用@bind-Value
时,它会在触发ValueChanged
的EventCallback时处理_myValue
字段的设置。而当您同时使用Value
和ValueChanged
时,您需要在处理程序方法中手动处理_myValue
字段的设置,即HandleValueChanged
。
这就是为什么您不能同时使用@bind-Value
和ValueChanged
的原因。因此,如果您想在Value属性更改时添加自定义逻辑,那么应该使用Value
和ValueChanged
。
>如何在出现错误时显示表单错误?
您可以使用MudForm
中的Errors
属性。
<MudForm @ref="form" @bind-Errors="@errors" @bind-IsValid="@success">
//...
</MudForm>
@code{
bool success;
string[] errors = { };
}
在您特定的代码中(不确定是否是有意的),您忽略了Validation
属性的赋值,每个要验证的属性都需要一个For
属性。
例如:
<MudForm Model="@ViewModel" Validation="@(viewModelValidator.ValidateValue)">
<MudSelect For="(() => ViewModel.BuildingId)" @bind-Value="@ViewModel.BuildingId" Label="Building" T="int?" Disabled="@IsFloorListDisabled" Required="true" ValueChanged="OnBuildingSelectionChanged">
<MudSelectItem T="int?" Value="null">Select Building</MudSelectItem>
@if (ViewModel.Buildings != null && ViewModel.Buildings.Count > 0)
{
@foreach (var building in ViewModel.Buildings)
{
<MudSelectItem T="int?" Value="@building.Id">@building.Name</MudSelectItem>
}
}
</MudSelect>
//...
</MudForm>
@code{
NewReservationViewModelValidation viewModelValidator = new();
}
英文:
>Why am I unable to use ValueChanged="OnBuildingSelectionChanged" together with @bind-Value="@ViewModel.BuildingId"?
@bind-Value
is kind of the short hand of using Value
and ValueChanged
. MS Docs.
<SomeComponent Value="_myValue" ValueChanged="HandleValueChanged"/>
<SomeComponent @bind-Value="_myValue"/>
When you use @bind-Value
it handles the setting of the _myValue
field when the ValueChanged
EventCallback is fired. Whereas, when you use Value
& ValueChanged
together, you need to handle the setting of the _myValue
field in the handler method i.e. HandleValueChanged
.
That's why you can't use both @bind-Value
and ValueChanged
at the same time. So if you want to add your own custom logic when the Value property changes then you should use Value
& ValueChanged
>How can I display the form errors if there are any?
You can use the Errors
property in MudForm.
<MudForm @ref="form" @bind-Errors="@errors" @bind-IsValid="@success">
//...
</MudForm>
@code{
bool success;
string[] errors = { };
}
In your specific code (unsure if intentional) you're missing assignment for the Validation
property and each property you're validating needs to have a For
property.
e.g.
<MudForm Model="@ViewModel" Validation="@(viewModelValidator.ValidateValue">
<MudSelect For="@(() => ViewModel.BuildingId)" @bind-Value="@ViewModel.BuildingId" Label="Building" T="int?" Disabled="@IsFloorListDisabled" Required="true" ValueChanged="OnBuildingSelectionChanged">
<MudSelectItem T="int?" Value="null">Select Building</MudSelectItem>
@if (ViewModel.Buildings != null && ViewModel.Buildings.Count > 0)
{
@foreach (var building in ViewModel.Buildings)
{
<MudSelectItem T="int?" Value="@building.Id">@building.Name</MudSelectItem>
}
}
</MudSelect>
//...
</MudForm>
@code{
NewReservationViewModelValidation viewModelValidator= new();
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论