diff --git a/src/BootstrapBlazor/Components/BaseComponents/BootstrapBlazorRoot.razor b/src/BootstrapBlazor/Components/BaseComponents/BootstrapBlazorRoot.razor
index b2c7f5ecd6b..7e9d6d825be 100644
--- a/src/BootstrapBlazor/Components/BaseComponents/BootstrapBlazorRoot.razor
+++ b/src/BootstrapBlazor/Components/BaseComponents/BootstrapBlazorRoot.razor
@@ -14,7 +14,7 @@
-
+
@foreach (var com in Generators)
{
@com.Generator()
diff --git a/src/BootstrapBlazor/Components/BootstrapBlazorRootOutlet/BootstrapBlazorRootContent.cs b/src/BootstrapBlazor/Components/BootstrapBlazorRootOutlet/BootstrapBlazorRootContent.cs
new file mode 100644
index 00000000000..63a2b2a63fd
--- /dev/null
+++ b/src/BootstrapBlazor/Components/BootstrapBlazorRootOutlet/BootstrapBlazorRootContent.cs
@@ -0,0 +1,96 @@
+// 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;
+
+///
+/// BootstrapBlazorRootContent Component
+///
+public class BootstrapBlazorRootContent : IComponent, IDisposable
+{
+ private object? _registeredIdentifier;
+
+ ///
+ /// Gets or sets the ID that determines which instance will render
+ /// the content of this instance.
+ ///
+ [Parameter] public string? RootName { get; set; }
+
+ ///
+ /// Gets or sets the ID that determines which instance will render
+ /// the content of this instance.
+ ///
+ [Parameter] public object? RootId { get; set; }
+
+ ///
+ /// Gets or sets the content.
+ ///
+ [Parameter]
+ public RenderFragment? ChildContent { get; set; }
+
+ [Inject]
+ private BootstrapBlazorRootRegisterService RootRegisterService { get; set; } = default!;
+
+ ///
+ ///
+ ///
+ ///
+ void IComponent.Attach(RenderHandle renderHandle)
+ {
+
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task IComponent.SetParametersAsync(ParameterView parameters)
+ {
+ parameters.SetParameterProperties(this);
+
+ object? identifier = null;
+
+ if (RootName is not null && RootId is not null)
+ {
+ throw new InvalidOperationException($"{nameof(BootstrapBlazorRootContent)} requires that '{nameof(RootName)}' and '{nameof(RootId)}' cannot both have non-null values.");
+ }
+ else if (RootName is not null)
+ {
+ identifier = RootName;
+ }
+ else if (RootId is not null)
+ {
+ identifier = RootId;
+ }
+ identifier ??= BootstrapBlazorRootOutlet.DefaultIdentifier;
+
+ if (!Equals(identifier, _registeredIdentifier))
+ {
+ if (_registeredIdentifier is not null)
+ {
+ RootRegisterService.RemoveProvider(_registeredIdentifier, this);
+ }
+
+ RootRegisterService.AddProvider(identifier, this);
+ _registeredIdentifier = identifier;
+ }
+
+ RootRegisterService.NotifyContentProviderChanged(identifier, this);
+ return Task.CompletedTask;
+ }
+
+ ///
+ ///
+ ///
+ public void Dispose()
+ {
+ if (_registeredIdentifier is not null)
+ {
+ RootRegisterService.RemoveProvider(_registeredIdentifier, this);
+ }
+ GC.SuppressFinalize(this);
+ }
+}
diff --git a/src/BootstrapBlazor/Components/BootstrapBlazorRootOutlet/BootstrapBlazorRootOutlet.cs b/src/BootstrapBlazor/Components/BootstrapBlazorRootOutlet/BootstrapBlazorRootOutlet.cs
new file mode 100644
index 00000000000..1eb29b987bb
--- /dev/null
+++ b/src/BootstrapBlazor/Components/BootstrapBlazorRootOutlet/BootstrapBlazorRootOutlet.cs
@@ -0,0 +1,144 @@
+// 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
+
+using Microsoft.AspNetCore.Components.Rendering;
+
+namespace BootstrapBlazor.Components;
+
+///
+/// BootstrapBlazorRootOutlet Component
+///
+public class BootstrapBlazorRootOutlet : IComponent, IDisposable
+{
+ private static readonly RenderFragment _emptyRenderFragment = _ => { };
+ private object? _subscribedIdentifier;
+ private RenderHandle _renderHandle;
+
+ ///
+ /// Gets the default identifier that can be used to subscribe to all instances.
+ ///
+ public static readonly object DefaultIdentifier = new();
+
+ [Inject]
+ private BootstrapBlazorRootRegisterService RootRegisterService { get; set; } = default!;
+
+ ///
+ /// Gets or sets the ID that determines which instances will provide
+ /// content to this instance.
+ ///
+ [Parameter]
+ public string? RootName { get; set; }
+
+ ///
+ /// Gets or sets the ID that determines which instances will provide
+ /// content to this instance.
+ ///
+ [Parameter]
+ public object? RootId { get; set; }
+
+ void IComponent.Attach(RenderHandle renderHandle)
+ {
+ _renderHandle = renderHandle;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task IComponent.SetParametersAsync(ParameterView parameters)
+ {
+ parameters.SetParameterProperties(this);
+
+ object? identifier = null;
+
+ if (RootName is not null && RootId is not null)
+ {
+ throw new InvalidOperationException($"{nameof(BootstrapBlazorRootOutlet)} requires that '{nameof(RootName)}' and '{nameof(RootId)}' cannot both have non-null values.");
+ }
+ else if (RootName is not null)
+ {
+ identifier = RootName;
+ }
+ else if (RootId is not null)
+ {
+ identifier = RootId;
+ }
+ identifier ??= DefaultIdentifier;
+
+ if (!Equals(identifier, _subscribedIdentifier))
+ {
+ if (_subscribedIdentifier is not null)
+ {
+ RootRegisterService.Unsubscribe(_subscribedIdentifier);
+ }
+
+ RootRegisterService.Subscribe(identifier, this);
+ _subscribedIdentifier = identifier;
+ }
+
+ RenderContent();
+ return Task.CompletedTask;
+ }
+
+ internal void ContentUpdated(BootstrapBlazorRootContent? provider)
+ {
+ RenderContent();
+ }
+
+ private void RenderContent()
+ {
+ _renderHandle.Render(BuildRenderTree);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ private void BuildRenderTree(RenderTreeBuilder builder)
+ {
+ if (_subscribedIdentifier is not null)
+ {
+ foreach (var content in RootRegisterService.GetProviders(_subscribedIdentifier))
+ {
+ builder.OpenComponent(0);
+ builder.SetKey(content);
+ builder.AddAttribute(1, BootstrapBlazorRootOutletContentRenderer.ContentParameterName, content.ChildContent ?? _emptyRenderFragment);
+ builder.CloseComponent();
+ }
+ }
+ }
+
+ ///
+ ///
+ ///
+ public void Dispose()
+ {
+ if (_subscribedIdentifier is not null)
+ {
+ RootRegisterService.Unsubscribe(_subscribedIdentifier);
+ }
+ GC.SuppressFinalize(this);
+ }
+
+ internal sealed class BootstrapBlazorRootOutletContentRenderer : IComponent
+ {
+ public const string ContentParameterName = "content";
+
+ private RenderHandle _renderHandle;
+
+ public void Attach(RenderHandle renderHandle)
+ {
+ _renderHandle = renderHandle;
+ }
+
+ public Task SetParametersAsync(ParameterView parameters)
+ {
+ var fragment = parameters.GetValueOrDefault(ContentParameterName)!;
+ _renderHandle.Render(fragment);
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs b/src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs
index 1a5b0327d7f..34090ffded9 100644
--- a/src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs
+++ b/src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs
@@ -36,6 +36,9 @@ public static IServiceCollection AddBootstrapBlazor(this IServiceCollection serv
services.TryAddSingleton();
services.TryAddSingleton(typeof(IDispatchService<>), typeof(DefaultDispatchService<>));
+ // BootstrapBlazorRootRegisterService 服务
+ services.AddScoped();
+
// Html2Pdf 服务
services.TryAddSingleton();
diff --git a/src/BootstrapBlazor/Services/BootstrapBlazorRootRegisterService.cs b/src/BootstrapBlazor/Services/BootstrapBlazorRootRegisterService.cs
new file mode 100644
index 00000000000..8c6bf5f0048
--- /dev/null
+++ b/src/BootstrapBlazor/Services/BootstrapBlazorRootRegisterService.cs
@@ -0,0 +1,130 @@
+// 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;
+
+///
+/// BootstrapBlazorRootRegisterService
+///
+public class BootstrapBlazorRootRegisterService
+{
+ private readonly Dictionary