如何将值从子组件 (RenderFragment) 传递到 C# Blazor 中的父页面?

How to pass value from Child component (RenderFragment) to Parent page in C# Blazor?

我有一个 Blazor 项目,它加载包含 Razor 组件的 DLL。为了在客户端呈现这些动态组件,我使用渲染树构建器从动态组件创建一个 RenderFragment 并将其放置在页面上以显示该组件。但是,我找不到在创建渲染树时绑定值的方法。通常,我可以使用下面的父子组件示例来传递数据,但是当将动态组件转换为 RenderFragment.

时,我不确定该怎么做

父组件

@page "/ParentComponent"

<h1>Parent Component</h1>

<ChildComponent @bind-Password="_password" />

@code {
    private string _password;
 }

子组件

<h1>Child Component</h1>

Password:

<input @oninput="OnPasswordChanged"
       required
       type="@(_showPassword ? "text" : "password")"
       value="@Password" />

<button class="btn btn-primary" @onclick="ToggleShowPassword">
    Show password
</button>

@code {
    private bool _showPassword;

    [Parameter]
    public string Password { get; set; }

    [Parameter]
    public EventCallback<string> PasswordChanged { get; set; }

    private Task OnPasswordChanged(ChangeEventArgs e)
    {
        Password = e.Value.ToString();
        return PasswordChanged.InvokeAsync(Password);
    }
    private void ToggleShowPassword()
    {
        _showPassword = !_showPassword;
    }
}

动态组件到 RenderFragment

下面的代码展示了我如何通过将组件转换为 RenderFragment 来在页面上显示该组件。你知道我如何在渲染树构建器中绑定变量,以将数据从动态组件传递到父页面吗?

注意:这个动态组件@dynamicComponent与上面的子组件相同,我想要它的密码数据。

@page "/{ComponentName}"
@inject IComponentService ComponentService

@if (render)
{
    @dynamicComponent()
    
    @_password;
}
    
@code{
    private string _password;
    
    [Parameter]
    public string ComponentName { get; set; }
    bool render = false;
    
    protected override void OnInitialized()
    {
        render = true;
        base.OnInitialized();
    }
    
    RenderFragment dynamicComponent() => builder =>
    {
        RazorComponentModel component = ComponentService.GetComponentByPage(ComponentName);
        builder.OpenComponent(0, component.Component);
        for (int i = 0; i < component.Parameters.Count; i++)
        {
            var attribute = component.Parameters.ElementAt(i);
            builder.AddAttribute(i + 1, attribute.Key, attribute.Value);
        }
        builder.CloseComponent();
    };
}

让我们先看看我的理解是否正确...您想创建一种组件渲染器,它获取组件的名称作为参数,并通过 IComponentService 获取组件的 Type,然后渲染它。我也猜测组件的Type可能是Type Child,你想知道如何在Index页面渲染它,并获取在Child组件中输入的密码,对吧? 下面的代码描述了如何做到这一点,但是我当然不能使用 IComponentService 服务来发现组件的类型,而是假设类型是 Child.

复制并运行 代码片段。测试它...它应该工作...

@page "/{ComponentName?}"

@using Microsoft.AspNetCore.Components.CompilerServices;

@if (render)
{
    @dynamicComponent
   
}

<p>Your password: @_password</p>
@code{
    private string _password;

    [Parameter]
    public string ComponentName { get; set; }

    bool render = false;

    protected override void OnInitialized()
    {
        render = true;
        base.OnInitialized();
    }

    RenderFragment dynamicComponent => builder =>
    {
        builder.OpenComponent(0, typeof(Child));
        builder.AddAttribute(1, "Password", _password);
        builder.AddAttribute(2, "PasswordChanged", 
            EventCallback.Factory.Create<string>(this, 
            RuntimeHelpers.CreateInferredEventCallback(this, __value => _password = __value, _password)));
        builder.CloseComponent();

    };
}

注意:您不应修改子组件中参数属性的值。 Blazor 中的参数属性是自动属性,这意味着您可以访问它们的值但不能更改它们。

此外,您不应该通过循环创建序列号。序列号应该是硬编码的。用谷歌搜索史蒂夫·安德森 (Steve Anderson) 的一篇文章中讨论的这个主题。