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

3
我有一个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在页面上显示该组件。请问如何在渲染树构建器中绑定一个变量,以从动态组件传递数据到父页面?

注意:这个动态组件@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();
    };
}
1个回答

2
让我先确认一下我的理解是否正确... 你想创建一种组件渲染器,它通过参数获取组件的名称,并通过 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在一篇文章中讨论的这个主题。

嗨 @enet。你的解决方案有效。谢谢。另外,如果我想绑定一个类,比如 PluginData,它有一个名为 _password 的字符串属性,我该如何修改你上面的解决方案来实现呢? - Ibrahim Timimi
抱歉,除非您详细解释您的请求,否则我不确定我理解您的意思。但是,您可以将参数传递给dynamicComponent方法,以便在代码中使用。您还可以在dynamicComponent方法之外定义属性,并从该方法中访问它们。 - enet
我的意思是,不是从子组件传递一个字符串数据到页面组件,而是从子组件传递一个包含多个属性例如用户名、密码等的对象到父组件,这样可行吗? - Ibrahim Timimi
我之前一直在处理这个问题,我把字符串属性替换成了一个包含多个属性的类。本来应该可以工作的,但是没有,所以我才向你求助。刚刚我又尝试了一下,发现自己犯了一个小错误。现在已经解决了,这样我就可以绑定更多的数据了。谢谢 @enet。 - Ibrahim Timimi
是的,您可以传递一个对象或一组对象... - enet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接