Blazor:绑定到 MultiSelectList(最好带有复选框)
Blazor: binding to a MultiSelectList (ideally with a checkbox)
正在试验 Blazor(服务器,如果这有什么不同的话),我很难绑定到 MultiSelectList 来工作....
一些背景知识:我正在处理 EF Core 并且有一个多对多关系,比方说人与车之间的关系。我目前正在加载显示现有详细信息的页面,并允许用户更新此页面。
所以在我的服务中,我从数据库中加载了我的个人实体,其中包括他们当前拥有的所有汽车的详细信息。我还加载了所有可用汽车的列表。我的服务方法然后创建一个 MultiSelectList 并将其添加到我的 ViewModel(返回到 Razor 页面):
服务方式
vm.CarSelector = new MultiSelectList(
allCars,
nameof(Car.CarId),
nameof(Car.Name),
person.OwnedCars.Select(oc => oc.CarId));
这是虚构的代码,但我希望你能看懂图片。调试时(在 Service 方法中)我可以看到这个 MultiSelectList 有一个条目用于每辆车,并且已经选择的那些显示为已选择。太棒了!
Blazor 剃刀页面
所以,这就是我的问题所在....我不知道如何将 Razor 控件的双向数据绑定到此对象。
- 我正在尝试使用
,但这可能不是最好的控件。
- 理想情况下(实际上,这更像是 "must have"),每个选项都应该有 CheckBox。
- 我想知道使用 MultiSelectList 是否真的能给我带来任何好处
我得到这个是为了与一个将 MultiSelectList 作为参数的组件一起工作。可能有更优雅的方法来实现这一点(如果您知道更好的方法,请更新)。
@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Mvc.Rendering
<div class="multiselect">
<div id="checkboxes">
@foreach (var item in this.Items)
{
<div>
<label for="@item.Value">
@if (item.Selected)
{
<input type="checkbox" id="@item.Value" checked="checked" @onchange="@((e) => CheckboxChanged(e, item.Value))" />
}
else
{
<input type="checkbox" id="@item.Value" @onchange="@((e) => CheckboxChanged(e, item.Value))" />
}
@item.Text
</label>
</div>
}
</div>
</div>
@code
{
[Parameter]
public MultiSelectList Items { get; set; } = null!;
private void CheckboxChanged(ChangeEventArgs e, string key)
{
var i = this.Items.FirstOrDefault(i => i.Value == key);
if (i != null)
{
i.Selected = (bool)e.Value;
}
}
}
复选框在 blazor 中有点不同。通常,您会在输入元素上使用 bind-value 属性,如下所示,但是,不建议这样做,因为您只能读取该值,而不能通过代码更改布尔值来更新 UI:
<input type="checkbox" @bind-value="@item.Selected"/>
相反,对复选框使用 @bind 语法,它更健壮并且可以双向工作(从代码更改绑定的布尔值并与 UI 上的复选框交互)。请参阅以下语法:
<input type="checkbox" @bind="@item.Selected"/>
bind 属性会自动将您的布尔值绑定到 html 元素的 "checked" 属性。
还要确保绑定到 "Selected" 属性 而不是 "Value" 属性。
使用内置绑定将避免像您在回答中那样手动设置事件的需要。您还可以摆脱 if/else 块并将您的代码合并到单个代码流中,因为您现在绑定到布尔值而不是手动设置选中的 属性。如果您仍然需要利用一个事件来触发某些进程(可能隐藏 UI 的部分以选中一个框),我建议使用 onclick 事件并为每一行手动传递多选项目。这是最终代码:
@foreach(var item in list)
{
<input type="checkbox" @bind="item.Selected" @onclick="(()=>handleClick(item))" />
}
@foreach(var item in list.Where(x=>x.Selected))
{
<p> Item @item.Text is Selected</p>
}
@code {
MultiSelectList list = new MultiSelectList(new List<Car> { new Car { Year = 2019, Make = "Honda", Model = "Accord" }, new Car { Make = "Honda", Model = "Civic", Year = 2019 } });
private void handleClick(SelectListItem item)
{
//Do something crazy
}
}
正在试验 Blazor(服务器,如果这有什么不同的话),我很难绑定到 MultiSelectList 来工作....
一些背景知识:我正在处理 EF Core 并且有一个多对多关系,比方说人与车之间的关系。我目前正在加载显示现有详细信息的页面,并允许用户更新此页面。
所以在我的服务中,我从数据库中加载了我的个人实体,其中包括他们当前拥有的所有汽车的详细信息。我还加载了所有可用汽车的列表。我的服务方法然后创建一个 MultiSelectList 并将其添加到我的 ViewModel(返回到 Razor 页面):
服务方式
vm.CarSelector = new MultiSelectList(
allCars,
nameof(Car.CarId),
nameof(Car.Name),
person.OwnedCars.Select(oc => oc.CarId));
这是虚构的代码,但我希望你能看懂图片。调试时(在 Service 方法中)我可以看到这个 MultiSelectList 有一个条目用于每辆车,并且已经选择的那些显示为已选择。太棒了!
Blazor 剃刀页面
所以,这就是我的问题所在....我不知道如何将 Razor 控件的双向数据绑定到此对象。
- 我正在尝试使用
,但这可能不是最好的控件。 - 理想情况下(实际上,这更像是 "must have"),每个选项都应该有 CheckBox。
- 我想知道使用 MultiSelectList 是否真的能给我带来任何好处
我得到这个是为了与一个将 MultiSelectList 作为参数的组件一起工作。可能有更优雅的方法来实现这一点(如果您知道更好的方法,请更新)。
@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Mvc.Rendering
<div class="multiselect">
<div id="checkboxes">
@foreach (var item in this.Items)
{
<div>
<label for="@item.Value">
@if (item.Selected)
{
<input type="checkbox" id="@item.Value" checked="checked" @onchange="@((e) => CheckboxChanged(e, item.Value))" />
}
else
{
<input type="checkbox" id="@item.Value" @onchange="@((e) => CheckboxChanged(e, item.Value))" />
}
@item.Text
</label>
</div>
}
</div>
</div>
@code
{
[Parameter]
public MultiSelectList Items { get; set; } = null!;
private void CheckboxChanged(ChangeEventArgs e, string key)
{
var i = this.Items.FirstOrDefault(i => i.Value == key);
if (i != null)
{
i.Selected = (bool)e.Value;
}
}
}
复选框在 blazor 中有点不同。通常,您会在输入元素上使用 bind-value 属性,如下所示,但是,不建议这样做,因为您只能读取该值,而不能通过代码更改布尔值来更新 UI:
<input type="checkbox" @bind-value="@item.Selected"/>
相反,对复选框使用 @bind 语法,它更健壮并且可以双向工作(从代码更改绑定的布尔值并与 UI 上的复选框交互)。请参阅以下语法:
<input type="checkbox" @bind="@item.Selected"/>
bind 属性会自动将您的布尔值绑定到 html 元素的 "checked" 属性。
还要确保绑定到 "Selected" 属性 而不是 "Value" 属性。
使用内置绑定将避免像您在回答中那样手动设置事件的需要。您还可以摆脱 if/else 块并将您的代码合并到单个代码流中,因为您现在绑定到布尔值而不是手动设置选中的 属性。如果您仍然需要利用一个事件来触发某些进程(可能隐藏 UI 的部分以选中一个框),我建议使用 onclick 事件并为每一行手动传递多选项目。这是最终代码:
@foreach(var item in list)
{
<input type="checkbox" @bind="item.Selected" @onclick="(()=>handleClick(item))" />
}
@foreach(var item in list.Where(x=>x.Selected))
{
<p> Item @item.Text is Selected</p>
}
@code {
MultiSelectList list = new MultiSelectList(new List<Car> { new Car { Year = 2019, Make = "Honda", Model = "Accord" }, new Car { Make = "Honda", Model = "Civic", Year = 2019 } });
private void handleClick(SelectListItem item)
{
//Do something crazy
}
}