繁体   English   中英

Blazor中class的双向组件参数绑定?

[英]Two-Way Component Parameter Binding on a class in Blazor?

我有一个 class MealsQueryInputs ,我想将其用作具有双向绑定功能的组件参数。

我能找到的所有演示和示例代码都使用内置原始类型,而不是 class。我可以让MS 演示工作,但我无法绑定到 class 工作。 甚至可以这样做吗?

我的组件FilterSortOptions.razor

using WhatIsForDinner.Shared.Models

<MudCheckBox Checked="@QueryInputs.Favorite" 
             Color="Color.Inherit" 
             CheckedIcon="@Icons.Material.Filled.Favorite" 
             UncheckedIcon="@Icons.Material.Filled.FavoriteBorder"
             T="bool"/>
<MudRating SelectedValue="@QueryInputs.Rating"/>
<MudButton OnClick="@(async () => await OnPropertyChanged())">Apply</MudButton>

@code {
    [Parameter]
    public MealsQueryInputs QueryInputs { get; set; }

    [Parameter]
    public EventCallback<MealsQueryInputs> QueryInputsChanged { get; set; }

    private async Task OnPropertyChanged()
    {
        await QueryInputsChanged.InvokeAsync(QueryInputs);
    }
}

正如 MrC 所说,您应该避免直接绑定到作为参数提供的数据。

这是一个简单的工作示例(不是 MudBlazor)来展示这个概念

https://blazorrepl.telerik.com/QQEnQjaO54LY3MYK35

您绑定到局部变量/属性,并尽量不要直接修改传入的数据。

我的组件


<h1>MyComponent</h1>

<label for="choice">Choose</label>
<input id="choice" type="checkbox" @bind-value=localValue  />

@code
{
    bool localValue
    {
        get => Data.SomeChoice;
        set {
            if (value != localValue)
            {
                localData = Data with { SomeChoice = value };
                InvokeAsync(ValueChanged);
            }
        }
    }
    ComplexObject localData;
    [Parameter] public ComplexObject Data { get; set; }
    [Parameter] public EventCallback<ComplexObject> DataChanged { get; set; }

    Task ValueChanged() => DataChanged.InvokeAsync(localData);
}

复杂对象

public record ComplexObject(bool SomeChoice, string SomeText);

主要的

@code
{
    ComplexObject data = new(false,"");
}

<MyComponent @bind-Data=data />

You have chosen @data.SomeChoice

以下是如何将 class 对象绑定到自定义 razor 组件

这是 FilterSortOptions 组件

<div>
    <label>Rating:</label>
    <input type="text" value=@QueryInputs.Rating @oninput=@(val=> {
           QueryInputs.Rating=val.Value.ToString();
           QueryInputsChanged.InvokeAsync(QueryInputs);
           }) />
</div>

<div>
    <label>Favourite:</label>
    <input type="checkbox" value=@QueryInputs.Rating @onchange=@(val=> {
           QueryInputs.Favourite=(bool)val.Value;
           QueryInputsChanged.InvokeAsync(QueryInputs);
           }) />
</div>

    @code {
    
        [Parameter]
        public MealsQueryInputs QueryInputs { get; set; }
    
        [Parameter]
        public EventCallback<MealsQueryInputs> QueryInputsChanged { get; set; }
    
    }

这里绑定的是model,为了简单起见Rating是string类型

public class MealsQueryInputs
{
    public bool Favourite { get; set; } = false;
    public string Rating { get; set; } = "0";
}

这是razor页面

<h3>Rating: @QueryInputs.Rating</h3>
<h3>Favourite: @QueryInputs.Favourite</h3>

<FilterSortOptions @bind-QueryInputs=@QueryInputs></FilterSortOptions>

@code {
    public MealsQueryInputs QueryInputs = new();
}

更新的答案

首先,如果您使用 object,那么您将传递对相同 object 的引用。因此,当您更新子组件中的 object 时,您将更新父组件正在使用的相同 object。 您不需要在回调中传回 object,除非您创建它的新副本。

其次,您没有将泥浆控件绑定到 object。

让我们看看你的代码:

<MudCheckBox Checked="@QueryInputs.Favorite" 
             Color="Color.Inherit" 
             CheckedIcon="@Icons.Material.Filled.Favorite" 
             UncheckedIcon="@Icons.Material.Filled.FavoriteBorder"
             T="bool"/>

Checked="@QueryInputs.Favorite"不会将控件绑定到字段。 它只是设置初始值。

我认为(我不使用 Mudblazor,它与标准的 Blazor 表单控件有点不同)你需要这样做:

<MudCheckBox @bind-Checked="@QueryInputs.Favorite"></MudCheckBox>

MudRating也是如此。

    <MudRating @bind-SelectedValue="@QueryInputs.Rating" />

然后是按钮:

<MudButton OnClick="@(async () => await OnPropertyChanged())">Apply</MudButton>

可以简化成这样。 您将异步方法包装在异步方法中。

<MudButton OnClick="OnPropertyChanged">Apply</MudButton>
// or
<MudButton OnClick="() => OnPropertyChanged()">Apply</MudButton>

原始答案

这里有几个问题:

  1. QueryInputs是一个Parameter ,因此永远不应被组件内的代码修改。 您最终会发现渲染器认为的值与实际值不匹配。

  2. 当父组件呈现时,它总是会导致重新呈现作为参数传递 class 的任何组件。 渲染器无法判断 class 是否已被修改,因此它应用了笨拙的解决方案 - 在组件上调用SetParametersAsync

一种解决方案是使用视图服务来保存数据和事件以通知更改。 一个版本的真相。 搜索“Blazor Notification Pattern”以获取有关如何实现此功能的示例。 如果你找不到你想要的,我会发布一些代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM