Blazor Server中Nullable Int的EditForm验证及点击事件异常
问题解决方案
问题1:Nullable Int空提交触发验证错误
原因
Blazor Server中使用[SupplyParameterFromForm]时,表单提交会将空字符串尝试绑定到int?类型属性,默认的InputNumber<int?>无法将空字符串解析为null,从而触发绑定验证错误。
解决方法
自定义适配int?的InputNumber组件,重写解析逻辑处理空字符串:
- 创建
InputNullableInt.razor文件:
@inherits InputNumber<int?> @code { protected override bool TryParseValueFromString(string? value, out int? result, out string? validationErrorMessage) { if (string.IsNullOrWhiteSpace(value)) { result = null; validationErrorMessage = null; return true; } return base.TryParseValueFromString(value, out result, out validationErrorMessage); } }
- 在Test页面中替换原
InputNumber为自定义组件:
<InputNullableInt id="myNullableInt" class="form-control" @bind-Value="TestModel.MyNullableInt" />
空值提交时会自动将MyNullableInt设为null,且不会触发验证错误。
问题2:表格列头点击事件无法触发
原因
原代码将点击事件绑定在<span>标签上,可能因组件渲染状态不稳定或事件上下文问题导致失效;同时[SupplyParameterFromForm]触发的参数更新也可能影响事件绑定有效性。
解决方法
- 将点击事件直接绑定到
<th>标签,添加交互样式确保可点击性:
<thead> <tr> <th role="button" style="cursor: pointer;" @onclick='() => ColumnHeaderClick("MyInt")'>Client</th> <th role="button" style="cursor: pointer;" @onclick='() => ColumnHeaderClick("MyString")'>My String</th> </tr> </thead>
- (可选)为表格行添加
@key稳定组件标识,避免重新渲染时事件绑定失效:
@foreach(var testSearchResult in TestSearchResults) { <tr @key="testSearchResult.MyInt"> <td>@testSearchResult.MyInt</td> <td>@testSearchResult.MyString</td> </tr> }
修改后列头点击事件可正常触发,调用ColumnHeaderClick方法输出日志。
完整修改后的代码示例
@page "/Test" @using Microsoft.Extensions.Logging @inject ILogger<Test> _logger <PageTitle>Test</PageTitle> <h1>Test</h1> @if(TestModel != null) { <EditForm Model="TestModel" OnValidSubmit="HandleValidSubmit" FormName="TestModel1"> <ValidationSummary /> <div class="row g-3"> <div class="col-md-4"> <label for="myNullableInt" class="form-label">Nullable Int</label> <InputNullableInt id="myNullableInt" class="form-control" @bind-Value="TestModel.MyNullableInt" /> </div> <div class="col-md-4"> <label for="myString" class="form-label">Nullable String</label> <InputText id="myString" class="form-control" @bind-Value="TestModel.MyString" /> </div> <div class="col-md-4"> <label for="MyInt" class="form-label">Int</label> <InputNumber id="MyInt" class="form-control" @bind-Value="TestModel.MyInt" /> </div> </div> <div class="mt-3"> <button type="submit" class="btn btn-primary">Search</button> </div> </EditForm> } @if(TestSearchResults != null) { <div class="mt-4"> <table class="table table-striped"> <thead> <tr> <th role="button" style="cursor: pointer;" @onclick='() => ColumnHeaderClick("MyInt")'>Client</th> <th role="button" style="cursor: pointer;" @onclick='() => ColumnHeaderClick("MyString")'>My String</th> </tr> </thead> <tbody> @foreach(var testSearchResult in TestSearchResults) { <tr @key="testSearchResult.MyInt"> <td>@testSearchResult.MyInt</td> <td>@testSearchResult.MyString</td> </tr> } </tbody> </table> </div> } @code { [SupplyParameterFromForm] public TestForm? TestModel { get; set; } private List<TestSearchResult>? TestSearchResults; protected override async Task OnInitializedAsync() { TestModel = TestModel ?? new TestForm(); _logger.LogInformation("In OnInitializedAsync"); } private async Task ColumnHeaderClick(string columnName) { _logger.LogInformation($"ColumnHeaderClick {columnName}"); } private async Task HandleValidSubmit() { _logger.LogInformation("In HandleValidSubmit"); TestSearchResults = new List<TestSearchResult>(); for (int i = TestModel.MyNullableInt.GetValueOrDefault(); i < 100; i++ ) { TestSearchResults.Add(new TestSearchResult() { MyInt = i, MyString = $"MyName{i}" }); } } public class TestForm { public int MyInt { get; set; } public int? MyNullableInt { get; set; } public string? MyString { get; set; } } public class TestSearchResult { public int MyInt { get; set; } public string MyString { get; set; } = string.Empty; } }
(配套InputNullableInt.razor代码如前文所述)
内容的提问来源于stack exchange,提问作者Tom Regan
相关产品推荐
相关产品推荐

