动态呈现的 ASP.NET Core Razor 组件

作者:Dave Brock

使用内置 DynamicComponent 组件按类型呈现组件。

DynamicComponent 适用于呈现组件,而无需循环访问可能的类型或使用条件逻辑。 例如,DynamicComponent 可以基于用户从下拉列表中选择的内容来呈现组件。

如下示例中:

  • componentType 指定类型。
  • parameters 指定要传递给 componentType 组件的组件参数。
<DynamicComponent Type="@componentType" Parameters="@parameters" />

@code {
    private Type componentType = ...;
    private IDictionary<string, object> parameters = ...;
}

有关传递参数值的详细信息,请参阅本文后面的传递参数部分。

使用 Instance 属性访问动态创建的组件实例:

<DynamicComponent Type="@typeof({COMPONENT})" @ref="dc" />

<button @onclick="Refresh">Refresh</button>

@code {
    private DynamicComponent? dc;

    private Task Refresh()
    {
        return (dc?.Instance as IRefreshable)?.Refresh();
    }
}

在上面的示例中:

  • {COMPONENT} 占位符是动态创建的组件类型。
  • IRefreshable 是开发人员为动态组件实例提供的示例接口。

示例

在下面的示例中,Razor 组件基于用户在四个可能值的下拉列表中选择的内容来呈现组件。

用户 spaceflight 运营商选择 共享 Razor 组件以呈现
Rocket Lab® Shared/RocketLab.razor
SpaceX® Shared/SpaceX.razor
ULA® Shared/UnitedLaunchAlliance.razor
Virgin Galactic® Shared/VirginGalactic.razor

Shared/RocketLab.razor:

<h2>Rocket Lab®</h2>

<p>
    Rocket Lab is a registered trademark of 
    <a href="https://www.rocketlabusa.com/">Rocket Lab USA Inc.</a>
</p>

Shared/SpaceX.razor:

<h2>SpaceX®</h2>

<p>
    SpaceX is a registered trademark of 
    <a href="https://www.spacex.com/">Space Exploration Technologies Corp.</a>
</p>

Shared/UnitedLaunchAlliance.razor:

<h2>United Launch Alliance®</h2>

<p>
    United Launch Alliance and ULA are registered trademarks of
    <a href="https://www.ulalaunch.com/">United Launch Alliance, LLC</a>.
</p>

Shared/VirginGalactic.razor:

<h2>Virgin Galactic®</h2>

<p>
    Virgin Galactic is a registered trademark of 
    <a href="https://www.virgingalactic.com/">Galactic Enterprises, LLC</a>.
</p>

Pages/DynamicComponentExample1.razor:

@page "/dynamiccomponent-example-1"

<h1><code>DynamicComponent</code> Component Example 1</h1>

<p>
    <label>
        Select your transport:
        <select @onchange="OnDropdownChange">
            <option value="">Select a value</option>
            <option value="@nameof(RocketLab)">Rocket Lab</option>
            <option value="@nameof(SpaceX)">SpaceX</option>
            <option value="@nameof(UnitedLaunchAlliance)">ULA</option>
            <option value="@nameof(VirginGalactic)">Virgin Galactic</option>
        </select>
    </label>
</p>

@if (selectedType is not null)
{
    <div class="border border-primary my-1 p-1">
        <DynamicComponent Type="@selectedType" />
    </div>
}

@code {
    private Type? selectedType;

    private void OnDropdownChange(ChangeEventArgs e)
    {
        selectedType = e.Value?.ToString()?.Length > 0 ? 
            Type.GetType($"BlazorSample.Shared.{e.Value}") : null;
    }
}

在上面的示例中:

  • 使用 nameof 运算符将组件名称作为常量字符串返回,将组件名称用作选项值。
  • 应用的命名空间为 BlazorSample。 更改命名空间以与应用的命名空间匹配。

传递参数

如果动态呈现的组件具有组件参数,请将它们作为 IDictionary<string, object> 传入 DynamicComponentstring 是参数的名称,object 是参数的值。

下面的示例配置组件元数据对象 (ComponentMetadata),以根据类型名称向动态呈现的组件提供参数值。 该示例只是可以采用的几种方法之一。 还可以从 web API、数据库或方法提供参数数据。 唯一的要求是方法返回 IDictionary<string, object>

ComponentMetadata.cs:

public class ComponentMetadata
{
    public string? Name { get; set; }
    public Dictionary<string, object> Parameters { get; set; } = 
        new Dictionary<string, object>();
}

以下 RocketLabWithWindowSeat 组件 (Shared/RocketLabWithWindowSeat.razor) 已对前面的示例进行了更新,其中包含名为 WindowSeat 的组件参数,用于指定乘客是否更喜欢航班上的靠窗座位:

Shared/RocketLabWithWindowSeat.razor:

<h2>Rocket Lab®</h2>

<p>
    User selected a window seat: @WindowSeat
</p>

<p>
    Rocket Lab is a trademark of 
    <a href="https://www.rocketlabusa.com/">Rocket Lab USA Inc.</a>
</p>

@code {
    [Parameter]
    public bool WindowSeat { get; set; }
}

在以下示例中:

  • 只有靠窗座位 (WindowSeat) 的 RocketLabWithWindowSeat 组件参数会接收 Window Seat 复选框的值。
  • 应用的命名空间为 BlazorSample。 更改命名空间以与应用的命名空间匹配。
  • 动态呈现的组件是应用 Shared 文件夹中的共享组件:
    • 本部分内容:RocketLabWithWindowSeat (Shared/RocketLabWithWindowSeat.razor)
    • 本文前面的示例部分所示的组件:
      • SpaceX (Shared/SpaceX.razor)
      • UnitedLaunchAlliance (Shared/UnitedLaunchAlliance.razor)
      • VirginGalactic (Shared/VirginGalactic.razor)

Pages/DynamicComponentExample2.razor:

@page "/dynamiccomponent-example-2"

<h1><code>DynamicComponent</code> Component Example 2</h1>

<p>
    <label>
        <input type="checkbox" @bind="WindowSeat" />
        Window Seat (Rocket Lab only)
    </label>
</p>

<p>
    <label>
        Select your transport:
        <select @onchange="OnDropdownChange">
            <option value="">Select a value</option>
            @foreach (var c in components)
            {
                <option value="@c.Key">@c.Value.Name</option>
            }
        </select>
    </label>
</p>

@if (selectedType is not null)
{
    <div class="border border-primary my-1 p-1">
        <DynamicComponent Type="@selectedType" 
            Parameters="@components[selectedType.Name].Parameters" />
    </div>
}

@code {
    private Dictionary<string, ComponentMetadata> components =
        new()
        {
            {
                "RocketLabWithWindowSeat",
                new ComponentMetadata
                {
                    Name = "Rocket Lab with Window Seat",
                    Parameters = new() { { "WindowSeat", false } }
                }
            },
            {
                "VirginGalactic",
                new ComponentMetadata { Name = "Virgin Galactic" }
            },
            {
                "UnitedLaunchAlliance",
                new ComponentMetadata { Name = "ULA" }
            },
            {
                "SpaceX",
                new ComponentMetadata { Name = "SpaceX" }
            }
        };
    private Type? selectedType;
    private bool windowSeat;

    private bool WindowSeat
    {
        get { return windowSeat; }
        set
        {
            windowSeat = value;
            components[nameof(RocketLabWithWindowSeat)].Parameters["WindowSeat"] = 
                windowSeat;
        }
    }

    private void OnDropdownChange(ChangeEventArgs e)
    {
        selectedType = e.Value?.ToString()?.Length > 0 ? 
            Type.GetType($"BlazorSample.Shared.{e.Value}") : null;
    }
}

事件回调 (EventCallback)

事件回调 (EventCallback) 可以传递给参数字典中的 DynamicComponent

ComponentMetadata.cs:

public class ComponentMetadata
{
    public string? Name { get; set; }
    public Dictionary<string, object> Parameters { get; set; } =
        new Dictionary<string, object>();
}

在每个动态呈现的组件中实现事件回调参数 (EventCallback)。

Shared/RocketLab2.razor:

<h2>Rocket Lab®</h2>

<p>
    Rocket Lab is a registered trademark of
    <a href="https://www.rocketlabusa.com/">Rocket Lab USA Inc.</a>
</p>

<button @onclick="OnClickCallback">
    Trigger a Parent component method
</button>

@code {
    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

Shared/SpaceX2.razor:

<h2>SpaceX®</h2>

<p>
    SpaceX is a registered trademark of
    <a href="https://www.spacex.com/">Space Exploration Technologies Corp.</a>
</p>

<button @onclick="OnClickCallback">
    Trigger a Parent component method
</button>

@code {
    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

Shared/UnitedLaunchAlliance2.razor:

<h2>United Launch Alliance®</h2>

<p>
    United Launch Alliance and ULA are registered trademarks of
    <a href="https://www.ulalaunch.com/">United Launch Alliance, LLC</a>.
</p>

<button @onclick="OnClickCallback">
    Trigger a Parent component method
</button>

@code {
    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

Shared/VirginGalactic2.razor:

<h2>Virgin Galactic®</h2>

<p>
    Virgin Galactic is a registered trademark of
    <a href="https://www.virgingalactic.com/">Galactic Enterprises, LLC</a>.
</p>

<button @onclick="OnClickCallback">
    Trigger a Parent component method
</button>

@code {
    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

在以下父组件示例中,ShowDTMessage 方法将一个包含当前时间的字符串分配给 message,并呈现 message 的值。

父组件在参数字典中传递回调方法 ShowDTMessage

  • string 键是回调方法的名称 OnClickCallback
  • object 值由 EventCallbackFactory.Create 为父回调方法 ShowDTMessage 创建。 请注意,C# 字段中不支持 this 关键字,因此 C# 属性用于参数字典。

对于以下组件,请更改 OnDropdownChange 方法中 BlazorSample 的命名空间名称,以匹配应用的命名空间。

Pages/DynamicComponentExample3.razor:

@page "/dynamiccomponent-example-3"

<h1><code>DynamicComponent</code> Component Example 3</h1>

<p>
    <label>
        Select your transport:
        <select @onchange="OnDropdownChange">
            <option value="">Select a value</option>
            <option value="@nameof(RocketLab2)">Rocket Lab</option>
            <option value="@nameof(SpaceX2)">SpaceX</option>
            <option value="@nameof(UnitedLaunchAlliance2)">ULA</option>
            <option value="@nameof(VirginGalactic2)">Virgin Galactic</option>
        </select>
    </label>
</p>

@if (selectedType is not null)
{
    <div class="border border-primary my-1 p-1">
        <DynamicComponent Type="@selectedType"
            Parameters="@Components[selectedType.Name].Parameters" />
    </div>
}

<p>
    @message
</p>

@code {
    private Type? selectedType;
    private string? message;

    private Dictionary<string, ComponentMetadata> Components
    {
        get
        {
            return new Dictionary<string, ComponentMetadata>()
            {
                {
                    "RocketLab2",
                    new ComponentMetadata
                    {
                        Name = "Rocket Lab",
                        Parameters =
                            new()
                            {
                                {
                                    "OnClickCallback",
                                    EventCallback.Factory.Create<MouseEventArgs>(
                                        this, ShowDTMessage)
                                }
                            }
                    }
                },
                {
                    "VirginGalactic2",
                    new ComponentMetadata
                    {
                        Name = "Virgin Galactic",
                        Parameters =
                            new()
                            {
                                {
                                    "OnClickCallback",
                                    EventCallback.Factory.Create<MouseEventArgs>(
                                        this, ShowDTMessage)
                                }
                            }
                    }
                },
                {
                    "UnitedLaunchAlliance2",
                    new ComponentMetadata
                    {
                        Name = "ULA",
                        Parameters =
                            new()
                            {
                                {
                                    "OnClickCallback",
                                    EventCallback.Factory.Create<MouseEventArgs>(
                                        this, ShowDTMessage)
                                }
                            }
                    }
                },
                {
                    "SpaceX2",
                    new ComponentMetadata
                    {
                        Name = "SpaceX",
                        Parameters =
                            new()
                            {
                                {
                                    "OnClickCallback",
                                    EventCallback.Factory.Create<MouseEventArgs>(
                                        this, ShowDTMessage)
                                }
                            }
                    }
                }
            };
        }
    }

    private void OnDropdownChange(ChangeEventArgs e)
    {
        selectedType = e.Value?.ToString()?.Length > 0 ?
            Type.GetType($"BlazorSample.Shared.{e.Value}") : null;
    }

    private void ShowDTMessage(MouseEventArgs e) =>
        message = $"The current DT is: {DateTime.Now}.";
}

避免 catch-all 参数

避免使用 catch-all 参数。 如果使用了 catch-all 参数,则 DynamicComponent 上的每个显式参数都会成为无法传递给动态子级的保留字。 传递给 DynamicComponent 的任何新参数都是中断性变更,因为它们会开始隐藏恰好同名的子组件参数。 调用方不太可能始终了解要传递给所有可能的动态子级的一组固定的参数名称。

商标

Rocket Lab 是 Rocket Lab USA Inc. 的注册商标。SpaceX 是 Space Exploration Technologies Corp. 的注册商标。United Launch Alliance 和 ULA 是 United Launch Alliance, LLC 的注册商标。 Virgin Galactic 是 Galactic Enterprises, LLC 的注册商标。

其他资源

DynamicComponent 适用于呈现组件,而无需循环访问可能的类型或使用条件逻辑。 例如,DynamicComponent 可以基于用户从下拉列表中选择的内容来呈现组件。

如下示例中:

  • componentType 指定类型。
  • parameters 指定要传递给 componentType 组件的组件参数。
<DynamicComponent Type="@componentType" Parameters="@parameters" />

@code {
    private Type componentType = ...;
    private IDictionary<string, object> parameters = ...;
}

有关传递参数值的详细信息,请参阅本文后面的传递参数部分。

使用 Instance 属性访问动态创建的组件实例:

<DynamicComponent Type="@typeof({COMPONENT})" @ref="dc" />

<button @onclick="Refresh">Refresh</button>

@code {
    private DynamicComponent? dc;

    private Task Refresh()
    {
        return (dc?.Instance as IRefreshable)?.Refresh();
    }
}

在上面的示例中:

  • {COMPONENT} 占位符是动态创建的组件类型。
  • IRefreshable 是开发人员为动态组件实例提供的示例接口。

示例

在下面的示例中,Razor 组件基于用户在四个可能值的下拉列表中选择的内容来呈现组件。

用户 spaceflight 运营商选择 共享 Razor 组件以呈现
Rocket Lab® Shared/RocketLab.razor
SpaceX® Shared/SpaceX.razor
ULA® Shared/UnitedLaunchAlliance.razor
Virgin Galactic® Shared/VirginGalactic.razor

Shared/RocketLab.razor:

<h2>Rocket Lab®</h2>

<p>
    Rocket Lab is a registered trademark of 
    <a href="https://www.rocketlabusa.com/">Rocket Lab USA Inc.</a>
</p>

Shared/SpaceX.razor:

<h2>SpaceX®</h2>

<p>
    SpaceX is a registered trademark of 
    <a href="https://www.spacex.com/">Space Exploration Technologies Corp.</a>
</p>

Shared/UnitedLaunchAlliance.razor:

<h2>United Launch Alliance®</h2>

<p>
    United Launch Alliance and ULA are registered trademarks of
    <a href="https://www.ulalaunch.com/">United Launch Alliance, LLC</a>.
</p>

Shared/VirginGalactic.razor:

<h2>Virgin Galactic®</h2>

<p>
    Virgin Galactic is a registered trademark of 
    <a href="https://www.virgingalactic.com/">Galactic Enterprises, LLC</a>.
</p>

Pages/DynamicComponentExample1.razor:

@page "/dynamiccomponent-example-1"

<h1><code>DynamicComponent</code> Component Example 1</h1>

<p>
    <label>
        Select your transport:
        <select @onchange="OnDropdownChange">
            <option value="">Select a value</option>
            <option value="@nameof(RocketLab)">Rocket Lab</option>
            <option value="@nameof(SpaceX)">SpaceX</option>
            <option value="@nameof(UnitedLaunchAlliance)">ULA</option>
            <option value="@nameof(VirginGalactic)">Virgin Galactic</option>
        </select>
    </label>
</p>

@if (selectedType is not null)
{
    <div class="border border-primary my-1 p-1">
        <DynamicComponent Type="@selectedType" />
    </div>
}

@code {
    private Type? selectedType;

    private void OnDropdownChange(ChangeEventArgs e)
    {
        selectedType = e.Value?.ToString()?.Length > 0 ? 
            Type.GetType($"BlazorSample.Shared.{e.Value}") : null;
    }
}

在上面的示例中:

  • 使用 nameof 运算符将组件名称作为常量字符串返回,将组件名称用作选项值。
  • 应用的命名空间为 BlazorSample。 更改命名空间以与应用的命名空间匹配。

传递参数

如果动态呈现的组件具有组件参数,请将它们作为 IDictionary<string, object> 传入 DynamicComponentstring 是参数的名称,object 是参数的值。

下面的示例配置组件元数据对象 (ComponentMetadata),以根据类型名称向动态呈现的组件提供参数值。 该示例只是可以采用的几种方法之一。 还可以从 web API、数据库或方法提供参数数据。 唯一的要求是方法返回 IDictionary<string, object>

ComponentMetadata.cs:

public class ComponentMetadata
{
    public string? Name { get; set; }
    public Dictionary<string, object> Parameters { get; set; } = 
        new Dictionary<string, object>();
}

以下 RocketLabWithWindowSeat 组件 (Shared/RocketLabWithWindowSeat.razor) 已对前面的示例进行了更新,其中包含名为 WindowSeat 的组件参数,用于指定乘客是否更喜欢航班上的靠窗座位:

Shared/RocketLabWithWindowSeat.razor:

<h2>Rocket Lab®</h2>

<p>
    User selected a window seat: @WindowSeat
</p>

<p>
    Rocket Lab is a trademark of 
    <a href="https://www.rocketlabusa.com/">Rocket Lab USA Inc.</a>
</p>

@code {
    [Parameter]
    public bool WindowSeat { get; set; }
}

在以下示例中:

  • 只有靠窗座位 (WindowSeat) 的 RocketLabWithWindowSeat 组件参数会接收 Window Seat 复选框的值。
  • 应用的命名空间为 BlazorSample。 更改命名空间以与应用的命名空间匹配。
  • 动态呈现的组件是应用 Shared 文件夹中的共享组件:
    • 本部分内容:RocketLabWithWindowSeat (Shared/RocketLabWithWindowSeat.razor)
    • 本文前面的示例部分所示的组件:
      • SpaceX (Shared/SpaceX.razor)
      • UnitedLaunchAlliance (Shared/UnitedLaunchAlliance.razor)
      • VirginGalactic (Shared/VirginGalactic.razor)

Pages/DynamicComponentExample2.razor:

@page "/dynamiccomponent-example-2"

<h1><code>DynamicComponent</code> Component Example 2</h1>

<p>
    <label>
        <input type="checkbox" @bind="WindowSeat" />
        Window Seat (Rocket Lab only)
    </label>
</p>

<p>
    <label>
        Select your transport:
        <select @onchange="OnDropdownChange">
            <option value="">Select a value</option>
            @foreach (var c in components)
            {
                <option value="@c.Key">@c.Value.Name</option>
            }
        </select>
    </label>
</p>

@if (selectedType is not null)
{
    <div class="border border-primary my-1 p-1">
        <DynamicComponent Type="@selectedType" 
            Parameters="@components[selectedType.Name].Parameters" />
    </div>
}

@code {
    private Dictionary<string, ComponentMetadata> components =
        new()
        {
            {
                "RocketLabWithWindowSeat",
                new ComponentMetadata
                {
                    Name = "Rocket Lab with Window Seat",
                    Parameters = new() { { "WindowSeat", false } }
                }
            },
            {
                "VirginGalactic",
                new ComponentMetadata { Name = "Virgin Galactic" }
            },
            {
                "UnitedLaunchAlliance",
                new ComponentMetadata { Name = "ULA" }
            },
            {
                "SpaceX",
                new ComponentMetadata { Name = "SpaceX" }
            }
        };
    private Type? selectedType;
    private bool windowSeat;

    private bool WindowSeat
    {
        get { return windowSeat; }
        set
        {
            windowSeat = value;
            components[nameof(RocketLabWithWindowSeat)].Parameters["WindowSeat"] = 
                windowSeat;
        }
    }

    private void OnDropdownChange(ChangeEventArgs e)
    {
        selectedType = e.Value?.ToString()?.Length > 0 ? 
            Type.GetType($"BlazorSample.Shared.{e.Value}") : null;
    }
}

事件回调 (EventCallback)

事件回调 (EventCallback) 可以传递给参数字典中的 DynamicComponent

ComponentMetadata.cs:

public class ComponentMetadata
{
    public string? Name { get; set; }
    public Dictionary<string, object> Parameters { get; set; } =
        new Dictionary<string, object>();
}

在每个动态呈现的组件中实现事件回调参数 (EventCallback)。

Shared/RocketLab2.razor:

<h2>Rocket Lab®</h2>

<p>
    Rocket Lab is a registered trademark of
    <a href="https://www.rocketlabusa.com/">Rocket Lab USA Inc.</a>
</p>

<button @onclick="OnClickCallback">
    Trigger a Parent component method
</button>

@code {
    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

Shared/SpaceX2.razor:

<h2>SpaceX®</h2>

<p>
    SpaceX is a registered trademark of
    <a href="https://www.spacex.com/">Space Exploration Technologies Corp.</a>
</p>

<button @onclick="OnClickCallback">
    Trigger a Parent component method
</button>

@code {
    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

Shared/UnitedLaunchAlliance2.razor:

<h2>United Launch Alliance®</h2>

<p>
    United Launch Alliance and ULA are registered trademarks of
    <a href="https://www.ulalaunch.com/">United Launch Alliance, LLC</a>.
</p>

<button @onclick="OnClickCallback">
    Trigger a Parent component method
</button>

@code {
    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

Shared/VirginGalactic2.razor:

<h2>Virgin Galactic®</h2>

<p>
    Virgin Galactic is a registered trademark of
    <a href="https://www.virgingalactic.com/">Galactic Enterprises, LLC</a>.
</p>

<button @onclick="OnClickCallback">
    Trigger a Parent component method
</button>

@code {
    [Parameter]
    public EventCallback<MouseEventArgs> OnClickCallback { get; set; }
}

在以下父组件示例中,ShowDTMessage 方法将一个包含当前时间的字符串分配给 message,并呈现 message 的值。

父组件在参数字典中传递回调方法 ShowDTMessage

  • string 键是回调方法的名称 OnClickCallback
  • object 值由 EventCallbackFactory.Create 为父回调方法 ShowDTMessage 创建。 请注意,C# 字段中不支持 this 关键字,因此 C# 属性用于参数字典。

对于以下组件,请更改 OnDropdownChange 方法中 BlazorSample 的命名空间名称,以匹配应用的命名空间。

Pages/DynamicComponentExample3.razor:

@page "/dynamiccomponent-example-3"

<h1><code>DynamicComponent</code> Component Example 3</h1>

<p>
    <label>
        Select your transport:
        <select @onchange="OnDropdownChange">
            <option value="">Select a value</option>
            <option value="@nameof(RocketLab2)">Rocket Lab</option>
            <option value="@nameof(SpaceX2)">SpaceX</option>
            <option value="@nameof(UnitedLaunchAlliance2)">ULA</option>
            <option value="@nameof(VirginGalactic2)">Virgin Galactic</option>
        </select>
    </label>
</p>

@if (selectedType is not null)
{
    <div class="border border-primary my-1 p-1">
        <DynamicComponent Type="@selectedType"
            Parameters="@Components[selectedType.Name].Parameters" />
    </div>
}

<p>
    @message
</p>

@code {
    private Type? selectedType;
    private string? message;

    private Dictionary<string, ComponentMetadata> Components
    {
        get
        {
            return new Dictionary<string, ComponentMetadata>()
            {
                {
                    "RocketLab2",
                    new ComponentMetadata
                    {
                        Name = "Rocket Lab",
                        Parameters =
                            new()
                            {
                                {
                                    "OnClickCallback",
                                    EventCallback.Factory.Create<MouseEventArgs>(
                                        this, ShowDTMessage)
                                }
                            }
                    }
                },
                {
                    "VirginGalactic2",
                    new ComponentMetadata
                    {
                        Name = "Virgin Galactic",
                        Parameters =
                            new()
                            {
                                {
                                    "OnClickCallback",
                                    EventCallback.Factory.Create<MouseEventArgs>(
                                        this, ShowDTMessage)
                                }
                            }
                    }
                },
                {
                    "UnitedLaunchAlliance2",
                    new ComponentMetadata
                    {
                        Name = "ULA",
                        Parameters =
                            new()
                            {
                                {
                                    "OnClickCallback",
                                    EventCallback.Factory.Create<MouseEventArgs>(
                                        this, ShowDTMessage)
                                }
                            }
                    }
                },
                {
                    "SpaceX2",
                    new ComponentMetadata
                    {
                        Name = "SpaceX",
                        Parameters =
                            new()
                            {
                                {
                                    "OnClickCallback",
                                    EventCallback.Factory.Create<MouseEventArgs>(
                                        this, ShowDTMessage)
                                }
                            }
                    }
                }
            };
        }
    }

    private void OnDropdownChange(ChangeEventArgs e)
    {
        selectedType = e.Value?.ToString()?.Length > 0 ?
            Type.GetType($"BlazorSample.Shared.{e.Value}") : null;
    }

    private void ShowDTMessage(MouseEventArgs e) =>
        message = $"The current DT is: {DateTime.Now}.";
}

避免 catch-all 参数

避免使用 catch-all 参数。 如果使用了 catch-all 参数,则 DynamicComponent 上的每个显式参数都会成为无法传递给动态子级的保留字。 传递给 DynamicComponent 的任何新参数都是中断性变更,因为它们会开始隐藏恰好同名的子组件参数。 调用方不太可能始终了解要传递给所有可能的动态子级的一组固定的参数名称。

商标

Rocket Lab 是 Rocket Lab USA Inc. 的注册商标。SpaceX 是 Space Exploration Technologies Corp. 的注册商标。United Launch Alliance 和 ULA 是 United Launch Alliance, LLC 的注册商标。 Virgin Galactic 是 Galactic Enterprises, LLC 的注册商标。

其他资源