我在 Blazor WebAssembly 中有一个通用选择器组件,它在选择选项时根据 onchange
事件调用函数。问题是 ChangeEventArgs
是对象类型,我无法将它转换为 TItem
而不会收到错误 Specified cast is not valid
。有没有解决的办法?如何让事件在这样的通用组件中正常工作?
@typeparam TItem
<select class="form-control selectpicker" value="@Selected" @onchange="Update">
@foreach (var item in Options)
{
<option value="@item">@item</option>
}
</select>
@code {
[Parameter] public List<TItem> Options { get; set; }
[Parameter] public TItem Selected { get; set; }
[Parameter] public EventCallback<TItem> SelectedChanged { get; set; }
private async Task Update(ChangeEventArgs e)
{
await SelectedChanged.InvokeAsync((TItem) e.Value); // e.Value is type object, cast to TItem fails
}
}
答案 0 :(得分:2)
如果您将复杂对象列表传递给选项,则这些对象无法直接呈现为 HTML,然后在选择后映射回源复杂对象。
运行以下命令并更改为第二个选择器(字符串)上的第 2 项,您将不会收到任何错误。在第 1 次选择时更改为第 2 项(OptionItem - 复杂),您将收到错误消息:
GenericSelector.razor
@typeparam TItem
<select class="form-control selectpicker" value="@Selected" @onchange="Update">
@foreach (var item in Options)
{
<option value="@item">@item</option>
}
</select>
@code {
[Parameter] public List<TItem> Options { get; set; }
[Parameter] public TItem Selected { get; set; }
[Parameter] public EventCallback<TItem> SelectedChanged { get; set; }
private async Task Update(ChangeEventArgs e)
{
await SelectedChanged.InvokeAsync((TItem)e.Value);
}
}
GenericSelectorPage.razor
@page "/genericselector"
@using NMW.Blazor.Components.GenericSelector
<GenericSelector TItem="OptionItem" Options=@Options />
<GenericSelector TItem="string" Options=@StringOptions />
@code {
List<OptionItem> Options { get; set; }
List<string> StringOptions { get; set; }
protected override void OnInitialized()
{
Options = new List<OptionItem>
{
new OptionItem { Id = "1", Text = "One"},
new OptionItem { Id = "2", Text = "Two"}
};
StringOptions = new List<string>
{
"One",
"Two"
};
base.OnInitialized();
}
public class OptionItem
{
public string Id { get; set; }
public string Text { get; set; }
}
}
在您的选择组件中声明接口:
public interface ISelectable
{
string Id { get; }
string Text { get; }
}
添加部分代码隐藏文件,以便您可以约束类型参数:
public partial class GenericSelector<TItem> where TItem : ISelectable
{ }
在您的复杂对象上实现 ISelectable:
public class ComplexOptionItem : ISelectable
{
// ISelectable Implementation
public string Id => MyId;
public string Text => MyText;
// Original Properties
public string MyId { get; set; }
public string MyText { get; set; }
}
如果您不想更改原始复杂对象以实现 ISelectable,则声明一个从 ComplexOptionItem 继承并实现 ISelectable 的 ComplexOptionView 类
public class ComplexOptionView : ComplexOptionItem, ISelectable
{
// ISelectable Implementation
public string Id => MyId;
public string Text => MyText;
}
更新您的通用选择器组件以使用 ISelectable 来获取用于渲染的显示属性,然后从传入的参数中检索复杂对象:
@typeparam TItem
<select class="form-control selectpicker" value="@Selected" @onchange="Update">
@foreach (ISelectable item in Options)
{
<option value="@item.Id">@item.Text</option>
}
</select>
@code {
[Parameter] public List<TItem> Options { get; set; }
[Parameter] public TItem Selected { get; set; }
[Parameter] public EventCallback<TItem> SelectedChanged { get; set; }
private async Task Update(ChangeEventArgs e)
{
// Retrieve original option based on Id
TItem selected = Options.Single(i => i.Id == e.Value);
// Raise the SelectedChanged event using the source object
await SelectedChanged.InvokeAsync(selected);
}
}
答案 1 :(得分:1)
您可以使用值为选择器指定 Item
:
<MySelector Options="availableTags" SelectedChanged="(val) => { selectedTag = availableTags.Single(x => x.Id == new Guid((string)val)); }">
<Item>
<option value="@context.Id">@context.Name</option>
</Item>
</MySelector>
现在,从 SelectedChanged
返回的值是 object
类型,但实际上是 string
,可以转换为 Guid
(因为值被指定为 { {1}},属于 context.Id
类型)。
Guid
是带有 availableTags
和 Tag
的 Name
类型列表:
Id
还要更改您的选择器以接受 public class Tag
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; }
}
并在更改时返回 Item
,也不需要 object
参数:
Selected