首页 > 解决方案 > Blazor 中的数据绑定:如何将值传播出组件?

问题描述

我有一个相当简单的组件,如下所示:

<form>
    <div class="form-group">
        <label for="sampleText">Sample Text</label>
        <input type="text"
               class="form-control"
               id="sampleText"
               aria-describedby="sampleTextHelp"
               placeholder="Enter a text"
               @bind="@Value" />
        <small id="sampleTextHelp" class="form-text text-muted">Enter a text to test the databinding</small>
    </div>
</form>
<p>You entered here: @Value</p>

@code {

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

我现在将它添加到这样的页面中:

<MVVMTest Value="@_value" />
<p>
    You entered in MVVMTest:
    @_value
</p>

@functions {
    private string _value;
}

当我在输入字段中输入文本时,它会正确更新为您在此处输入:但未传播到 *您在 MVVMTest 中输入”:

MVVM 不工作

我该怎么做才能正确传播它?

我可以考虑在文本更改时将其连接到组件内部,但这似乎是一种笨拙而迂回的方式Action<string>[Parameter]是必须这样做,还是有更好的方法?

跟进 1

Issac 的答案不起作用,因为它绊倒@bind-value:oninput="@((e) => ValueChanged.Invoke(e.Value))"Cannot convert lambda expression to type 'object' because it is not a delegate type.

我不得不以这种迂回的方式做到这一点:

<form>
    <div class="form-group">
        <label for="sampleText">Sample Text</label>
        <input type="text"
               class="form-control"
               id="sampleText"
               aria-describedby="sampleTextHelp"
               placeholder="Enter a text"
               @bind="@Value" />
        <small id="sampleTextHelp" class="form-text text-muted">Enter a text to test the databinding</small>
    </div>
</form>
<p>You entered here: @Value</p>

@code {

    private string _value;

    [Parameter]
    public string Value {
        get => _value;
        set {
            if(Equals(value, _value)) {
                return;
            }
            _value = value;
            OnValueChanged.InvokeAsync(value).GetAwaiter().GetResult();
        }
    }

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

并像这样使用它:

@inject HttpClient http
@page "/test"
<div class="top-row px-4">
    Test Page
</div>

<div class="content px-4">
    <MVVMTest Value="@_value" OnValueChanged="@(v => _value = v)" />
    <p>
        You entered in MVVMTest:
        @_value
    </p>
</div>

@functions {
    private string _value;
}

不漂亮,但它有效。我的“真实”组件更复杂,因为更改的值会触发对底层 ASP.net 核心服务的调用,因此我必须仔细检测谁更改了哪些内容以避免无限循环。

如果 Blazor 支持类似 XAML/WPF 的 MVVM 肯定会更好......

跟进 2

我回到了 Issac 的解决方案,并通过额外的演员,我得到了它的工作:

<form>
    <div class="form-group">
        <label for="sampleText">Sample Text</label>
        <input type="text"
               class="form-control"
               id="sampleText"
               aria-describedby="sampleTextHelp"
               placeholder="Enter a text"
               value="@Value"
               oninput="@((Func<ChangeEventArgs, Task>)(async e => await OnValueChanged.InvokeAsync(e.Value as string)))" />
        <small id="sampleTextHelp" class="form-text text-muted">Enter a text to test the databinding</small>
    </div>
</form>
<p>You entered here: @Value</p>

@code {

    private string _value;

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

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

用法:

<MVVMTest Value="@_value" OnValueChanged="@(v => _value = v)" />
<p>
    You entered in MVVMTest:
    @_value
</p>

@functions {
    private string _value;
}

这已经是 Blazor 中的一个已知问题。我上周已经绊倒了,我也在 VS 开发者论坛上发布了解决方法。

标签: c#mvvmdata-bindingblazor

解决方案


您需要添加一个 EventCallback 参数来执行此操作:

@code {

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

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

阅读数据绑定/组件参数部分


推荐阅读