在Blazor中如何在父组件中获取子组件绑定的值

16

假设有一个名为cinput.cshtml的子组件

<input type="text" bind="@username">

@functions{
string username;
}

同时还有被称为 pform.cshtml 的父组件

<cinput></cinput>
<input type="text" bind="@email">
<input type="button" onclick="@onsubmit">

@functions{

string email;

public void onsubmit(){
   //Call api
}
}

那么问题是如何在父组件中获取用户名(username)的值?

3个回答

21

你需要按照以下步骤操作:

  1. 在你的子组件中定义一个EventCallback委托属性:
[Parameter] protected  EventCallback<string>  OnUserNameChanged { get; set; }

该属性将包含对在父组件上定义的方法的委托。

  1. 在您的子组件中定义一个属性和一个支持变量:
    private string username;
    public string UserName
    {
        get => username;
        set
        {
            username = value;
            // Invoke the delegate passing it the changed value
            OnUserNameChanged?.Invoke(value);
        }
    } 
  1. 在你的父组件中定义一个方法,当用户名称改变时从子组件调用该方法:
    public async void UserNameChanged(string username)
       {
          // Gets and consume the user name
       }
  • 以下是子组件在父组件中的使用方式: 请注意,我们将方法名称分配给属性OnUserNameChanged,该属性是您的子组件中的委托属性。
  •      <cinput OnUserNameChanged="UserNameChanged" ></cinput>
            <input type="text" bind="@email">
            <input type="button" onclick="@onsubmit">
    

    希望这可以帮到你...

    这是Steve Anderson关于ref的说法:

    使用案例

    其预期使用案例是允许父组件向子组件发出命令,例如“显示”或“重置”。

    即使如此,从架构上来说,这仍然是一种妥协,因为对于您的子组件而言,保持无状态(也就是说,不对除参数以外的任何状态做出反应)会更加清晰。在这种情况下,甚至在理论上都不可能发出“行动”而不是通过改变其子元素的参数来实现,这种情况下根本不需要ref。

    强烈不建议您使用ref来改变子组件的状态。相反,始终使用普通的声明性参数将数据传递给子组件。这将自动在正确的时间重新呈现子组件。我们正在朝着更改组件上参数表示方式的方向前进,以便默认情况下它们是封装的,不可能从外部读取/写入。


    这对于单个属性来说是相当大的开销。而且实时更新并不是必需的(有一个提交按钮)。我需要在一个更大的组合示例中看到它的表现如何。 - H H
    这是在Blazor(和Angular)中编写SPA的方法。模仿Steve Anderson非常容易...代码片段中没有提交按钮,也没有任何暗示要使用它的意图。没有启用数据提交的表单元素,并且请记住,这是一个通过Ajax与后端通信的SPA Web应用程序。您不会以传统方式发布...祝您有美好的一天。 - enet
    仅仅使用 ref 访问值就简单得多了,我不明白有什么意义。 - smj
    @ Syed Mohammed SMJ,请参见我上面答案的最后一部分中的回复... - enet
    2
    如果我想在同一个表单中使用多个子实例,这个解决方案是否可行? - smj

    2

    BLAZOR WAY:

    要以 Blazor 的方式完成此操作,首先使用 Blazor 组件。下面的示例使用 SingleSelect.razor 组件,该组件是一个简化的 HTML Select 元素。

    该组件通过标签引用,该标签由 Visual Studio 根据 Razor 组件文件的名称自动生成,因此在本例中,标签将为 <SingleSelect>

    为了从子组件获取值,父组件创建指向子组件的引用变量。

    这是通过在父组件中创建子组件的局部变量来完成的:

    private SingleSelect singleSelect;

    然后在子标记中进行链接:

    <SingleSelect @ref="singleSelect" Options="SingleSelectOptions"></SingleSelect>

    这允许通过利用参考变量引用子数据:

    singleSelect.SelectedOption.Value

    以下页面提供了一个完整的示例。

    Index.razor 页面

    @page "/"
    
    <h3>Single Select Example</h3>
    <h5 class="mt-2">Make your selection</h5>
    <SingleSelect @ref="singleSelect" Options="SingleSelectOptions"></SingleSelect>
    <button class="btn btn-primary mt-2" @onclick="SubmitSingleSelect">Submit</button>
    
    <h5 class="mt-2">The following was selected:</h5>
    <p>@singleSelectResult</p>
    
    @code
    {
        public partial class Index
        {
           
            SingleSelect singleSelect;
            string singleSelectResult;
            List<SingleSelectOption> SingleSelectOptions = new List<SingleSelectOption>
            {
                new SingleSelectOption{ Id=1, Value="One"},
                new SingleSelectOption{ Id=2, Value="Two"},
                new SingleSelectOption{ Id=3, Value="Three"},
                new SingleSelectOption{ Id=4, Value="Four"},
                new SingleSelectOption{ Id=5, Value="Five"},
                new SingleSelectOption{ Id=6, Value="Six"},
                new SingleSelectOption{ Id=7, Value="Seven"},
                new SingleSelectOption{ Id=8, Value="Eight"},
                new SingleSelectOption{ Id=9, Value="Nine"},
                new SingleSelectOption{ Id=10, Value="Ten"},
                new SingleSelectOption{ Id=11, Value="Eleven"},
            };
    
    
            private void SubmitSingleSelect()
            {
                singleSelectResult = singleSelect.SelectedOption.Value;
            }
    
        }
    }
    
    

    SingleSelect.razor page

    <div class="container">
        <div class="row">
            <div class="col-3">
                <select id="NotSelected" class="border" multiple="multiple" size="@boxSize" style="width: 200px">
                    @foreach (var option in Options)
                    {
                        <option id="@option.Id" @onclick="@(() => Select(option))">@option.Value</option>
                    }
                </select>
            </div>
        </div>
    </div>
    
    @code 
    {
        [Parameter]
        public List<SingleSelectOption> Options { get; set; } = new List<SingleSelectOption>();
        public SingleSelectOption SelectedOption { get; set; } = new SingleSelectOption { Id = 0, Value = " "};
    
        private int boxSize = 5;
    
        private void Select(SingleSelectOption option)
        {
            SelectedOption = option;
        }
    
        public class SingleSelectOption
        {
            public int Id { get; set; }
            public string Value { get; set; }
        }
    }
    

    0

    所以我做了这样的事情

    cinput.cshtml

    <input type="text" bind="@username">
    
    @functions{
    string username;
    
    string getUsername(){
     return username;
    }
    
    }
    

    在pform.cshtml中

    <cinput ref="_cinput"></cinput>
    <input type="text" bind="@email">
    <input type="button" onclick="@onsubmit">
    
    @functions{
    
    string email;
    Cinput _cinput
    
    public void onsubmit(){
       //get username
       string uname = _cinput.getUsername();
       //Call api
    
    }
    }
    

    https://learn.microsoft.com/en-us/aspnet/core/razor-components/components?view=aspnetcore-3.0#capture-references-to-components


    1
    这个对我来说完全有效,甚至可以获取绑定的值。 - smj
    它现在运行良好,但只是暂时的...在未来的 Blazor 版本中,从上面听起来似乎不会起作用。听起来,Blazor 的开发人员提前告诉我们,使用 Ref 是这种情况下不好的方式。太糟糕了,因为这种方法更容易。 - infocyde
    我只希望新的方式更容易,就像现在这样。 - smj
    大家好,你们有关于这个的任何消息吗?因为获取输入值太容易了。 - António Garcez
    1
    .NET 6.0已经发布,而ref仍然是一个重要的概念,供您参考。 - Kyle J V

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