Blazor 组件双向数据绑定

Posted

技术标签:

【中文标题】Blazor 组件双向数据绑定【英文标题】:Blazor Component TwoWay Databinding 【发布时间】:2019-10-01 16:56:41 【问题描述】:

我以这种方式制作了 Blazor 组件:

<input bind-value-oninput="Title" />


@functions 

    [Parameter] string Title  get; set; 

    [Parameter] EventCallback<string> TitleChanged  get; set; 

家长:

@page "/fetchdata"

Parent:<input bind-value-oninput="Title" /> - Child:<Comp bind-Title="Title"></Comp>



@functions 
    string Title;


正如预期的那样,编辑父输入会将其值传播给组件,但反之亦然,这是设计对吗?

我通过此编辑实现了双向行为:

<input bind-value-oninput="Title" />


@functions 
    string _Title  get; set; 
    [Parameter] string Title 

    
        get  return _Title; 
        set
        
            Console.WriteLine($"value->_Title");



            if (_Title != value)
            
                _Title = value;
                TitleChanged.InvokeAsync(value);
            


        
    

    [Parameter] EventCallback<string> TitleChanged  get; set; 

这是实现双向数据绑定的最佳实践吗?那么 TitleChanged 必须手动调用,对吧?是不是像WPF的PropertyChanged?

没有

     if (_Title != value)

代码进入循环,有人可以解释为什么吗?

【问题讨论】:

【参考方案1】:

这是组件之间的双向数据绑定。这种行为(或限制)是设计使然。你所做的是解决它的正确方法,我可以冒昧地说,一个最佳实践,至少根据史蒂夫安德森,其他人可能会建议不同的方法,例如服务类。

对发生的事情的一些解释:当您对父组件应用更改时,会触发更改事件,组件的状态发生了变化,并且应该重新渲染组件。若要重新呈现父组件,Blazor 会自动调用 StateHasChanged 方法。但是当子组件的状态发生变化时,父组件对此一无所知,我们应该通知它。同样,在我看来,为此使用事件回调是一个好习惯......

希望这有帮助....

编辑....

一般来说,参数流是向下的,即从父级到 孩子,而不是另一个方向,因为渲染流进入 那个方向。这就是为什么没有办法传递参数的原因 上游(例如,布局),因为那时没有单一的 定义的渲染顺序。

史蒂夫桑德森

Marco:我不明白为什么对父级调用 StateHasChanged 会导致数据从父级流向子级,而不是相反。

首先,您无需手动调用 StateHasChanged 方法。每当触发输入事件时都会自动调用它;即在按下每个键盘键之后。并调用它来重新渲染组件(父)。 (注意:很容易认为输入标签是一个 html 输入标签元素,但事实并非如此。)

至于为什么不相反:我认为 SteveSanderson 的引述说得很清楚。

当您想将值(这实际上是一个参数,而不是 Attribute 属性)传递给父组件时,您需要使用不同的机制,例如事件(由 SteveSanderson 推荐;并像在 Angular 中一样工作)。下面是如何执行的示例代码。 重要提示:当父组件的状态从子组件改变时,我们应该通过手动调用StateHasChanged方法让父组件知道它的状态已经改变并且应该重新渲染。使用 Action 委托时确实如此,尽管我认为 EventCallback 委托应该自动调用 StateHasChanged。

组件 A.cshtml

// Define a method in the parent component which will be called 
// from the child component when the user tap the button residing 
// in the child component. This method has a string parameter passed
// from the child component
public void GetValueFromChild(string value)
 
        // Do somethig with value
   

组件 B.cshtml

// When the user click the button the method GetValueFromChild
// defined on the parent component is called

<button class="btn" onclick=@(() => OnAddValue("some string value"))>Add</button>

    @functions

    // Define an Action delegate property which stores a reference
    // to A.GetValueFromChild
    // Parameters
    [Parameter] Action<string> OnAddValue get; set; 

A.cshtml

// Here (in the parent component) you place the child component and
// set its OnAddValue to the name of the method to be called
<B OnAddValue = "GetValueFromChild"></B> 

如果对您有帮助,请将我的回答标记为已接受 希望这会有所帮助...

【讨论】:

感谢您的回答,我做了更多的测试,但我不明白为什么在父级上调用 StateHasChanged 会导致数据从父级流向子级而不是相反.我在孩子身上设置了输入,现在正如你所说,父母不知道,我希望在父母上调用 StateHasChanged 会导致父母知道孩子身上发生的数据变化,应用绑定并更新它的输入。发生的事情是子级使用父级数据进行更新。 在您的评论回复上方查看答案。

以上是关于Blazor 组件双向数据绑定的主要内容,如果未能解决你的问题,请参考以下文章

Blazor University 组件 — 双向绑定

双向数据绑定到单例服务Blazor服务器端

Blazor - 组件包装和数据绑定

双向绑定和后台更新不重新渲染组件

Angular 手动实现ngModal数据双向绑定

vue组件双向绑定key的作用