英文:
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();
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论