diff --git a/src/BootstrapBlazor.Server/Components/Samples/Cascaders.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Cascaders.razor.cs index 08e94557b7e..448c0e76a18 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Cascaders.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Cascaders.razor.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the Apache 2.0 License // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone @@ -88,9 +88,9 @@ private EventItem[] GetEvents() => } ]; - private void OnValidate() + private async Task OnValidate() { - ValidateForm1.Validate(); + await ValidateForm1.ValidateAsync(); } /// diff --git a/src/BootstrapBlazor.Server/Components/Samples/ValidateForms.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/ValidateForms.razor.cs index d2fdb00a200..2793819e325 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/ValidateForms.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/ValidateForms.razor.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the Apache 2.0 License // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone @@ -249,10 +249,9 @@ private void OnValidateReset() [NotNull] private ValidateForm? ValidatorForm { get; set; } - private Task OnValidator() + private async Task OnValidator() { - ValidatorForm.Validate(); - return Task.CompletedTask; + await ValidatorForm.ValidateAsync(); } [NotNull] diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index ba0651b92a8..5467994fe63 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@  - 10.2.1-beta04 + 10.2.1-beta05 diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs b/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs index f4136cd20ee..f5fa0d02ff1 100644 --- a/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs +++ b/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs @@ -704,7 +704,8 @@ private async Task ClickEditButton(TItem item) private async Task ClickUpdateButtonCallback() { // 验证 InCell 模式下的表单 - if (!_inCellValidateForm.Validate()) + var valid = await _inCellValidateForm.ValidateAsync(); + if (!valid) { return; } diff --git a/src/BootstrapBlazor/Components/ValidateForm/BootstrapBlazorDataAnnotationsValidator.cs b/src/BootstrapBlazor/Components/ValidateForm/BootstrapBlazorDataAnnotationsValidator.cs index e75d5306d44..095fb7503d6 100644 --- a/src/BootstrapBlazor/Components/ValidateForm/BootstrapBlazorDataAnnotationsValidator.cs +++ b/src/BootstrapBlazor/Components/ValidateForm/BootstrapBlazorDataAnnotationsValidator.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the Apache 2.0 License // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone @@ -47,10 +47,23 @@ protected override void OnInitialized() AddEditContextDataAnnotationsValidation(); } + private TaskCompletionSource? _tcs; /// /// 手动验证表单方法 /// /// + internal async Task ValidateAsync() + { + _tcs = new(false); + var ret = CurrentEditContext.Validate(); + var valid = await _tcs.Task; + return ret && valid; + } + + /// + /// 手动验证表单方法 + /// + [ExcludeFromCodeCoverage] internal bool Validate() => CurrentEditContext.Validate(); private void AddEditContextDataAnnotationsValidation() @@ -93,6 +106,11 @@ private async Task ValidateModel(EditContext editContext, ValidationMessageStore } } editContext.NotifyValidationStateChanged(); + + if (_tcs != null) + { + _tcs.TrySetResult(validationResults.Count == 0); + } } private async Task ValidateField(EditContext editContext, ValidationMessageStore messages, FieldIdentifier field, IServiceProvider provider) diff --git a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs index 5ce1d425d9e..54133010822 100644 --- a/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs +++ b/src/BootstrapBlazor/Components/ValidateForm/ValidateForm.razor.cs @@ -649,11 +649,18 @@ private async Task OnInvalidSubmitForm(EditContext context) private EditContext? _formlessEditContext; /// - /// 验证方法 用于代码调用触发表单验证 + /// 同步验证方法 用于代码调用触发表单验证(不支持某些组件的异步验证) /// - /// + [Obsolete("已弃用,请使用 ValidateAsync 方法。Deprecated. Please use the ValidateAsync method.")] + [ExcludeFromCodeCoverage] public bool Validate() => Validator.Validate(); + /// + /// 异步验证方法 用于代码调用触发表单验证(支持异步验证) + /// + /// + public Task ValidateAsync() => Validator.ValidateAsync(); + /// /// 通知属性改变方法 /// diff --git a/test/UnitTest/Components/DateTimePickerTest.cs b/test/UnitTest/Components/DateTimePickerTest.cs index 5095a367d37..1c87db701f5 100644 --- a/test/UnitTest/Components/DateTimePickerTest.cs +++ b/test/UnitTest/Components/DateTimePickerTest.cs @@ -1286,7 +1286,7 @@ await cut.InvokeAsync(() => Assert.Equal("02/15/2024", model.DateTime.Value.ToString("MM/dd/yyyy")); // 录入非法数值 Validate 通过 - var valid = cut.Instance.Validate(); + var valid = await cut.InvokeAsync(cut.Instance.ValidateAsync); Assert.True(valid); } diff --git a/test/UnitTest/Components/DateTimeRangeTest.cs b/test/UnitTest/Components/DateTimeRangeTest.cs index 3aab91e009a..3fb41e13d5a 100644 --- a/test/UnitTest/Components/DateTimeRangeTest.cs +++ b/test/UnitTest/Components/DateTimeRangeTest.cs @@ -479,13 +479,12 @@ public async Task InValidateForm_Ok() cut.Contains("class=\"form-label\""); // 验证 - var validate = true; - await cut.InvokeAsync(() => validate = cut.Instance.Validate()); + var validate = await cut.InvokeAsync(cut.Instance.ValidateAsync); Assert.False(validate); var range = cut.FindComponent(); var clear = range.Find(".is-clear"); - clear.Click(); + await cut.InvokeAsync(() => clear.Click()); range.Render(pb => { @@ -504,8 +503,7 @@ public async Task InValidateForm_Ok() { pb.Add(a => a.Model, foo); }); - validate = false; - await cut.InvokeAsync(() => validate = cut.Instance.Validate()); + validate = await cut.InvokeAsync(cut.Instance.ValidateAsync); Assert.True(validate); } diff --git a/test/UnitTest/Components/InputNumberTest.cs b/test/UnitTest/Components/InputNumberTest.cs index 78686218ed3..fba11fb55e6 100644 --- a/test/UnitTest/Components/InputNumberTest.cs +++ b/test/UnitTest/Components/InputNumberTest.cs @@ -242,7 +242,7 @@ await cut.InvokeAsync(() => }); Assert.Equal(1, model.Count); - var valid = cut.Instance.Validate(); + var valid = await cut.InvokeAsync(cut.Instance.ValidateAsync); Assert.False(valid); await cut.InvokeAsync(() => @@ -250,7 +250,7 @@ await cut.InvokeAsync(() => input.Change("t2"); }); Assert.Equal(1, model.Count); - valid = cut.Instance.Validate(); + valid = await cut.InvokeAsync(cut.Instance.ValidateAsync); Assert.False(valid); await cut.InvokeAsync(() => @@ -259,7 +259,7 @@ await cut.InvokeAsync(() => }); Assert.Equal(2, model.Count); - valid = cut.Instance.Validate(); + valid = await cut.InvokeAsync(cut.Instance.ValidateAsync); Assert.True(valid); }