[英]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>
這里有幾個問題:
QueryInputs
是一個Parameter
,因此永遠不應被組件內的代碼修改。 您最終會發現渲染器認為的值與實際值不匹配。
當父組件呈現時,它總是會導致重新呈現作為參數傳遞 class 的任何組件。 渲染器無法判斷 class 是否已被修改,因此它應用了笨拙的解決方案 - 在組件上調用SetParametersAsync
。
一種解決方案是使用視圖服務來保存數據和事件以通知更改。 一個版本的真相。 搜索“Blazor Notification Pattern”以獲取有關如何實現此功能的示例。 如果你找不到你想要的,我會發布一些代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.