在自定义组件中包装 MudBlazor 组件 - @bind-Value 的问题

我是 blazor 的新手,我遇到了 MudBlazor 组件。这些都很棒,所以我决定在我的项目中实现它们。我想做的是将我在自己的自定义组件中使用的每个 MudBlazor 组件包装起来,这样如果我将来更改任何内容都会很简单(就像我已经决定从 Radzen 更改为 MudBlazor 的情况一样)。在大多数情况下,这是相当直接的,除了 @bind-Value 属性。我似乎无法弄清楚如何让它工作。这是我包装 MudBlazor“MudTextField”的自定义组件。

<MudTextField @bind-Value="@BindTo" Label="@Label" Variant="@Variant" Margin="@Margin"></MudTextField>

@code {
    private string bindingValue;

    [Parameter]
    public string BindTo
    {
        get => bindingValue;
        set
        {
            if (bindingValue == value) return;
            bindingValue = value;
            BindToChanged.InvokeAsync(value);
        }
    }

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

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

    [Parameter] public Variant Variant { get; set; } = Variant.Outlined;

    [Parameter] public Margin Margin { get; set; } = Margin.Dense;
}

这是行不通的。当我在调用我的自定义组件时设置 BindTo 参数时,我可以看到 set 属性中的代码被调用,并且 bindingValue 被正确设置,但我绑定到的对象上的属性没有被更新。我需要对 BindToChanged 参数执行其他操作吗?我在研究这个问题时看到另一个例子中使用了它,但我真的不明白它应该做什么。任何帮助,将不胜感激。

谢谢!

stack overflow Wrapping MudBlazor component inside custom component - Issue with @bind-Value
原文答案
author avatar

接受的答案

您需要通过 ValueValueChangedValueExpression 的三元组传递到 MudBlazor 组件。

我不使用 MudBlazor,所以无法正确测试它,而且我只知道如何将其构建为 RenderFragment 而不是在 Razor 中构建,但像这样的东西应该可以工作:

    public class MyMudBlazorTextField<TValue> : ComponentBase
    {
        [Parameter]
        public TValue? Value { get; set; }

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

        [Parameter] public Expression<Func<TValue>>? ValueExpression { get; set; }

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

        [Parameter] public Variant Variant { get; set; } = Variant.Outlined;

        [Parameter] public Margin Margin { get; set; } = Margin.Dense;

        protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            builder.OpenComponent<MudTextField<TValue>>(0);
            builder.AddAttribute(1, "Variant", this.Variant);
            builder.AddAttribute(2, "Margin", this.Margin);
            builder.AddAttribute(3, "Label", this.Label);
            builder.AddAttribute(4, "Value", this.Value);
            builder.AddAttribute(5, "ValueChanged", EventCallback.Factory.Create(this, this.ValueChanged));
            builder.CloseComponent();
        }
    }

然后你使用正常的 @bind-value

<MyMudBlazorTextField @bind-value=myfield ...../>

你很可能白白付出了很多努力。 Variant 和 Margin 之类的东西都是 MudBlazor 特有的,而 MudBlazor 有一些特定的构建方式,所以除非你在你的组件中修复这些东西,否则你就是在混淆你的通用组件的水域(借口双关语)!

### 更新

我从 MudBlazor Dashboard 项目的 Account 页面提取了一些代码。它使用此函数设置文本字段:

        public static void CreateMudTextField_0<T>(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.String __arg0, int __seq1, global::MudBlazor.Variant __arg1, int __seq2, T __arg2, int __seq3, global::Microsoft.AspNetCore.Components.EventCallback<T> __arg3)
        {
        __builder.OpenComponent<global::MudBlazor.MudTextField<T>>(seq);
        __builder.AddAttribute(__seq0, "Label", __arg0);
        __builder.AddAttribute(__seq1, "Variant", __arg1);
        __builder.AddAttribute(__seq2, "Value", __arg2);
        __builder.AddAttribute(__seq3, "ValueChanged", __arg3);
        __builder.CloseComponent();
        }

在此基础上,我对代码进行了一些调整。


答案:

作者头像

我找到了另一种使用 .razor 组件让它工作的解决方案。我本来很接近。 .razor 组件中的代码是正确的。问题是我在调用绑定属性时如何传递它。我很抱歉没有在我最初的请求中包含那部分代码。我认为这无关紧要。

我试图这样称呼它:

<MyInput BindTo=@"MyBindProperty" />

但我需要将它传递给@bind-BindTo

<MyInput @bind-BindTo=@"MyBindProperty" />

来自 MrC aka Shaun Curtis 的答案也以纯 c# 形式出色地工作。