如何绑定到使用组件标签帮助器呈现的组件的值

问题描述

我需要在现有的视图和页面上使用一些作为剃刀组件构建的自定义输入,但是似乎无法使用组件标签助手来使其工作。例如,我最初使用(来自https://chrissainty.com/creating-bespoke-input-components-for-blazor-from-scratch/)进行测试的组件代码会导致异常,因为ValueExpression最终为null(据我所知,没有使用标签助手进行绑定的选项)。如果然后我自己设置ValueExpression,则会导致json异常(检测到对象周期)。我认为可能是因为将参数从标记帮助器移动到基础组件的机制不支持Func 对象?不确定。

我是不是尝试使用标记帮助程序?我在其他地方使用它来呈现独立的组件(例如整个EditForm),这似乎工作正常,但是如何使它在此特定用例中正常工作使我:(

我希望控件呈现在.cshtml文件内部:

<component type="typeof(MyComponent)" render-mode="ServerPrerendered" param-ValueExpression="(Func<string>)(() => LocalProperty)" />

MyComponent.razor

<input class="_fieldCssClasses" value="@Value" @oninput="HandleInput" />

@if (_showValidation) {
    <div class="validation-message">You must provide a name</div>
}

@code {
    private FieldIdentifier _fieldIdentifier;
    private string _fieldCssClasses => EditContext?.FieldCssClass(_fieldIdentifier) ?? "";
    private bool _showValidation = false;

    [CascadingParameter] private EditContext EditContext { get; set; }

    [Parameter] public string Value { get; set; }
    [Parameter] public EventCallback<string> ValueChanged { get; set; }
    [Parameter] public Expression<Func<string>> ValueExpression { get; set; }
    [Parameter] public bool required { get; set; }

    protected override void OnInitialized() {
        _fieldIdentifier = FieldIdentifier.Create(ValueExpression);
    }

    private async Task HandleInput(ChangeEventArgs args) {
        await ValueChanged.InvokeAsync(args.Value.ToString());

        if (EditContext != null) {
            EditContext.NotifyFieldChanged(_fieldIdentifier);
        } else if (required) {
            _showValidation = string.IsNullOrWhiteSpace(args.Value.ToString());
        }
    }
}

解决方法

因此,为解决此问题,我在内部组件周围制作了一个用例专用的包装器组件,确保还传递一个ID,以使内部组件将分配给其呈现的输入的名称和id属性(使其在提交表单时“绑定”),然后在页面/视图中包含包装器组件。包装器仅满足内部组件的依赖关系,如果依赖关系更复杂(例如Func 对象),则组件标签帮助程序不提供这种机制。

MyComponentWrapper.razor:

<div class='purdy'>
    <MyComponent Id="@Id" @bind-Value="Value"></MyComponent>
</div>
...
@code {
    [Parameter]
    public string Id { get; set; }
    [Parameter]
    public string Value { get; set; }
    ...
}

MyContainingPage.cshtml:

<component type="typeof(MyComponentWrapper)" render-mode="ServerPrerendered" param-Id="myFormInput" param-Value="LocalProperty" />
...