diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index 5f06f943ea2..3eef7f75957 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@  - 10.3.2-beta01 + 10.3.2-beta02 diff --git a/src/BootstrapBlazor/Components/Dialog/Dialog.razor b/src/BootstrapBlazor/Components/Dialog/Dialog.razor index 8d5ab2cb92b..53b5bb91b97 100644 --- a/src/BootstrapBlazor/Components/Dialog/Dialog.razor +++ b/src/BootstrapBlazor/Components/Dialog/Dialog.razor @@ -2,7 +2,7 @@ @inherits BootstrapComponentBase @for (var index = 0; index < DialogParameters.Keys.Count; index++) { diff --git a/src/BootstrapBlazor/Components/Dialog/Dialog.razor.cs b/src/BootstrapBlazor/Components/Dialog/Dialog.razor.cs index 9a89b66abca..7d555585284 100644 --- a/src/BootstrapBlazor/Components/Dialog/Dialog.razor.cs +++ b/src/BootstrapBlazor/Components/Dialog/Dialog.razor.cs @@ -19,6 +19,7 @@ public partial class Dialog : IDisposable private Modal? _modal = null; private Func? _onShownAsync = null; private Func? _onCloseAsync = null; + private Func>? _onClosingAsync = null; private readonly Dictionary, (bool IsKeyboard, bool IsBackdrop, Func? OnCloseCallback)> DialogParameters = []; private Dictionary? _currentParameter; @@ -87,6 +88,8 @@ private async Task Show(DialogOption option) } }; + _onClosingAsync = option.OnClosingAsync; + _isKeyboard = option.IsKeyboard; _isBackdrop = option.IsBackdrop; _isFade = option.IsFade; diff --git a/src/BootstrapBlazor/Components/Dialog/DialogOption.cs b/src/BootstrapBlazor/Components/Dialog/DialogOption.cs index 1fde2fb4105..d3f583dd64a 100644 --- a/src/BootstrapBlazor/Components/Dialog/DialogOption.cs +++ b/src/BootstrapBlazor/Components/Dialog/DialogOption.cs @@ -9,7 +9,7 @@ namespace BootstrapBlazor.Components; /// Dialog 对话框组件 /// Dialog component /// -public class DialogOption +public class DialogOption : ICloseable { /// /// 获得/设置 关联的 Modal 实例 @@ -192,11 +192,15 @@ public class DialogOption public string? CloseButtonText { get; set; } /// - /// 获得/设置 关闭对话框回调方法 - /// Gets or sets the callback method for closing the dialog + /// /// public Func? OnCloseAsync { get; set; } + /// + /// + /// + public Func>? OnClosingAsync { get; set; } + /// /// 获得/设置 是否自动关闭对话框(保存成功后) 默认值为 true /// Gets or sets whether to automatically close the dialog after saving successfully, default is true diff --git a/src/BootstrapBlazor/Components/Modal/IClosable.cs b/src/BootstrapBlazor/Components/Modal/IClosable.cs new file mode 100644 index 00000000000..6feb58b5096 --- /dev/null +++ b/src/BootstrapBlazor/Components/Modal/IClosable.cs @@ -0,0 +1,25 @@ +// 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 + +namespace BootstrapBlazor.Components; + +/// +/// 可关闭接口 +/// the closable interface +/// +public interface ICloseable +{ + /// + /// 获得/设置 弹出窗口关闭时的回调委托 + /// Gets or sets the callback delegate when the popup is closed + /// + Func? OnCloseAsync { get; set; } + + /// + /// 关闭之前回调方法 返回 true 时关闭弹窗 返回 false 时阻止关闭弹窗 + /// Callback Method Before Closing. Return true to close, false to prevent closing + /// + Func>? OnClosingAsync { get; set; } +} diff --git a/src/BootstrapBlazor/Components/Modal/Modal.razor.cs b/src/BootstrapBlazor/Components/Modal/Modal.razor.cs index 0d4cf2782c0..40b0b284908 100644 --- a/src/BootstrapBlazor/Components/Modal/Modal.razor.cs +++ b/src/BootstrapBlazor/Components/Modal/Modal.razor.cs @@ -11,7 +11,7 @@ namespace BootstrapBlazor.Components; /// Modal 组件 /// Modal component /// -public partial class Modal +public partial class Modal : ICloseable { [Inject] [NotNull] @@ -77,15 +77,13 @@ public partial class Modal public Func? OnShownAsync { get; set; } /// - /// 获得/设置 弹出窗口关闭时的回调委托 - /// Gets or sets the callback delegate when the popup is closed + /// /// [Parameter] public Func? OnCloseAsync { get; set; } /// - /// 关闭之前回调方法 返回 true 时关闭弹窗 返回 false 时阻止关闭弹窗 - /// Callback Method Before Closing. Return true to close, false to prevent closing + /// /// [Parameter] public Func>? OnClosingAsync { get; set; } diff --git a/src/BootstrapBlazor/Extensions/PropertyInfoExtensions.cs b/src/BootstrapBlazor/Extensions/PropertyInfoExtensions.cs index a13210851eb..ad06c5f7eb5 100644 --- a/src/BootstrapBlazor/Extensions/PropertyInfoExtensions.cs +++ b/src/BootstrapBlazor/Extensions/PropertyInfoExtensions.cs @@ -26,7 +26,7 @@ public static bool IsStatic(this PropertyInfo p) /// /// 判断属性是否可以写入扩展方法 - /// Determines whether the property can be written to extension method + /// Determines whether the property can be written to /// /// public static bool IsCanWrite(this PropertyInfo p) => p.CanWrite && !p.IsInit(); diff --git a/src/BootstrapBlazor/Utils/BootstrapDynamicComponent.cs b/src/BootstrapBlazor/Utils/BootstrapDynamicComponent.cs index d55d33532d5..8fcc6d24036 100644 --- a/src/BootstrapBlazor/Utils/BootstrapDynamicComponent.cs +++ b/src/BootstrapBlazor/Utils/BootstrapDynamicComponent.cs @@ -62,14 +62,14 @@ public RenderFragment RenderEditTemplate(string? modelParameterN { var index = 0; builder.OpenComponent(index++, componentType); + modelParameterName ??= "Model"; + var modelProperty = componentType.GetPropertyByName(modelParameterName); + if (modelProperty.HasParameterAttribute(typeof(TModel))) + { + builder.AddAttribute(index++, modelParameterName, model); + } if (parameters != null) { - modelParameterName ??= "Model"; - var modelProperty = componentType.GetPropertyByName(modelParameterName); - if (modelProperty.HasParameterAttribute(typeof(TModel))) - { - builder.AddAttribute(index++, modelParameterName, model); - } foreach (var p in parameters) { builder.AddAttribute(index++, p.Key, p.Value); diff --git a/test/UnitTest/Components/DialogTest.cs b/test/UnitTest/Components/DialogTest.cs index 79e509b9c98..585abacc9c6 100644 --- a/test/UnitTest/Components/DialogTest.cs +++ b/test/UnitTest/Components/DialogTest.cs @@ -583,6 +583,22 @@ await cut.InvokeAsync(() => dialog.ShowCloseDialog("Clos await cut.InvokeAsync(() => dialog.ShowExceptionDialog(null, new Exception("Test"))); await cut.InvokeAsync(() => modal.Instance.CloseCallback()); #endregion + + // OnClosing + var closing = false; + await cut.InvokeAsync(() => dialog.Show(new DialogOption() + { + OnClosingAsync = () => + { + closing = true; + return Task.FromResult(false); + } + })); + + // 由于返回 false 所以关窗方法被阻止 + await cut.InvokeAsync(() => modal.Instance.Close()); + Assert.True(closing); + await cut.InvokeAsync(() => modal.Instance.CloseCallback()); } private class MockValidateFormDialog : ComponentBase diff --git a/test/UnitTest/Core/TestBase.cs b/test/UnitTest/Core/TestBase.cs index d6b4c46c936..401a29b37db 100644 --- a/test/UnitTest/Core/TestBase.cs +++ b/test/UnitTest/Core/TestBase.cs @@ -13,16 +13,12 @@ public TestBase() { Context = new BunitContext(); Context.JSInterop.Mode = JSRuntimeMode.Loose; - - Context.Services.AddMockEnvironment(); } public void Dispose() { -#pragma warning disable CA2012 // 由于 bUnit 2.0 继承了 IAsyncDisposable 接口,因此此处调用 DisposeAsync 方法 - Context.DisposeAsync(); -#pragma warning restore CA2012 + Context.DisposeAsync().AsTask().Wait(); GC.SuppressFinalize(this); } } diff --git a/test/UnitTest/Extensions/IServiceCollectionExtensions.cs b/test/UnitTest/Extensions/IServiceCollectionExtensions.cs index 4b9faa37ccf..9371a8de223 100644 --- a/test/UnitTest/Extensions/IServiceCollectionExtensions.cs +++ b/test/UnitTest/Extensions/IServiceCollectionExtensions.cs @@ -4,8 +4,6 @@ // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.FileProviders; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace Microsoft.Extensions.DependencyInjection; @@ -29,12 +27,6 @@ public static IServiceCollection AddConfiguration(this IServiceCollection servic return services; } - public static IServiceCollection AddMockEnvironment(this IServiceCollection services) - { - services.AddSingleton(); - return services; - } - public static ILoggingBuilder AddMockLoggerProvider(this ILoggingBuilder builder) { return builder.AddProvider(new TestLoggerProvider()); @@ -61,15 +53,4 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except } } - - class MockEnvironment : IHostEnvironment - { - public string EnvironmentName { get; set; } = "Development"; - - public string ApplicationName { get; set; } = "Test"; - - public string ContentRootPath { get; set; } = "UnitTest"; - - public IFileProvider ContentRootFileProvider { get; set; } = null!; - } }