是否可以在Blazor子组件中双向绑定集合
TLDR;当执行ValueChanged
EventCallBack
处理程序时,对象中类型列表的属性被设置为null
,这会抛出NullReferenceException
s,因为它在页面中被设置为null
。
我有以下例子:
public class Person
{
public string FullName { get; set; }
public List<string> NickNames { get; set; } = new List<string>();
}
主页面:Index.razor
<h1>@Mario.FullName - @string.join('-', Mario.NickNames)</h1>
<NicknamesListComponent @bind-Nicknames="Mario.NickNames" />
@code{
public Person Mario { get; set; } =
new Person() { FullName = "Mario", NickNames = new List<string> {"Super", "Mama" , "Mia"} }
}
子组件:NicknamesListComponent.razor
<ul>
@for(int i = 0; i < Nicknames.Count; i++)
{
@var index = i;
<li>
@Nicknames[index]
<a @onclick="() => RemoveNickname(index)">Remove</a>
</li>
}
</ul>
@code {
[Parameter]
public List<string> Nicknames { get; set; }
[Parameter]
public EventCallback<List<string>> NicknamesChanged { get; set; }
public async Task RemoveNickname(int index)
{
Nicknames.RemoveAt(index);
//////////////////////////////////////////////////////////
// When executing NicknamesChanged. the User.Nicknames property is completly cleared and
// set to NULL... this throws exceptions everywhere in the index.blazor
await NicknamesChanged.InvokeAsync();
}
}
如果我删除NicknamesChanged
,那么带有Delete按钮的列表就可以工作。。。但这一次没有通知家长更改,昵称保持不变。。。
null是因为您使用void调用NicknamesChanged.InvokeAsync()
。
双向绑定工作:
await NicknamesChanged.InvokeAsync(Nicknames);
旁注:我认为这是一个打字错误,但string.Join(...)
不是string.join(...)
如果你解决了这两个问题,你的代码就会正常工作。然而
避免for循环问题的更好方法:
<ul>
@foreach(var nickname in Nicknames)
{
<li @key=nickname>
@nickname
<a @onclick="() => RemoveNickname(nickname)">Remove</a>
</li>
}
</ul>
@code {
[Parameter]
public List<string> Nicknames { get; set; }
[Parameter]
public EventCallback<List<string>> NicknamesChanged { get; set; }
public async Task RemoveNickname(string nickname)
{
Nicknames.Remove(nickname);
await NicknamesChanged.InvokeAsync(Nicknames);
}
}
应该使用@key
,因为您可能会删除错误的昵称。
Repl
您必须在NicknamesChanged上返回NickNames,建议不要更改NicknamesParameter。请改用局部变量。
更新后的代码为:
<ul>
@for (int i = 0; i < Nicknames.Count; i++)
{
var index = i;
<li>
@Nicknames[index]
<a @onclick="() => RemoveNickname(index)">Remove</a>
</li>
}
</ul>
@code {
[Parameter]
public List<string> Nicknames { get; set; }
[Parameter]
public EventCallback<List<string>> NicknamesChanged { get; set; }
public async Task RemoveNickname(int index)
{
Nicknames.RemoveAt(index);
await NicknamesChanged.InvokeAsync(Nicknames);
}
}