我select在 Blazor 中定义了一个自定义组件,如下所示:
public class BetterInputSelect<TItem> : InputBase<TItem>
{
[Parameter]
public IEnumerable<TItem> Data { get; set; } = new List<TItem>();
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.OpenElement(0, "select");
builder.AddMultipleAttributes(1, AdditionalAttributes);
builder.AddAttribute(2, "class", CssClass);
builder.AddAttribute(3, "value", BindConverter.FormatValue(CurrentValueAsString));
builder.AddAttribute(4, "onchange", EventCallback.Factory.CreateBinder<string>(
this, value => CurrentValueAsString = value, CurrentValueAsString!, null));
foreach (var item in this.Data)
{
builder.OpenElement(5, "option");
builder.AddAttribute(6, "value", item!.ToString());
builder.AddContent(7, this.FindDisplayName(item));
builder.CloseElement();
}
builder.CloseElement();
}
protected override bool TryParseValueFromString(string? value, out TItem result, out string validationErrorMessage)
{
// Check for enums first.
if (typeof(TItem).IsEnum && BindConverter.TryConvertTo(value, CultureInfo.CurrentCulture, out TItem? parsedValue))
{
result = parsedValue!;
validationErrorMessage = null!;
return true;
}
// Other types here
// ...
result = default!;
validationErrorMessage = $"The {FieldIdentifier.FieldName} field is not valid.";
return false;
}
private string FindDisplayName(TItem value)
{
return value switch
{
null => string.Empty,
Enum @enum => @enum.GetDescription(),
_ => value.ToString() ?? string.Empty
};
}
}
Run Code Online (Sandbox Code Playgroud)
然后可以像这样使用:
<BetterInputSelect Data="@Reasons" @bind-Value="@Reason" />
Run Code Online (Sandbox Code Playgroud)
其中Reasons和Reason的定义如下:
public SomeReason Reason { get; set; }
private IEnumerable<SomeReason>? Reasons { get; set; }
...
public enum SomeReason
{
...
}
Run Code Online (Sandbox Code Playgroud)
只要所绑定的值@bind-Value不可为空,这种方法就很有效。当我做:
public SomeReason? Reason { get; set; }
Run Code Online (Sandbox Code Playgroud)
我收到编译时错误:
[CS0411] The type arguments for method
'TypeInference.CreateBetterInputSelect_0<TItem>(RenderTreeBuilder, int, int, IEnumerable<TItem>, int, TItem, int, EventCallback<TItem>, int, Expression<Func<TItem>>)'
cannot be inferred from the usage. Try specifying the type arguments explicitly.
Run Code Online (Sandbox Code Playgroud)
我是否可以简单地不绑定到可为空的属性,或者有没有办法让编译器对我错过的事情感到高兴?
如果我尝试像这样显式定义类型:
<BetterInputSelect
Data="@Reasons"
@bind-Value="@Reason"
TItem="SomeReason" />
Run Code Online (Sandbox Code Playgroud)
然后我得到以下编译器错误:
[CS1503] Argument 1: cannot convert from 'SomeReason?' to 'SomeReason'
[CS1503] Argument 2: cannot convert from 'Microsoft.AspNetCore.Components.EventCallback<SomeReason?>' to 'Microsoft.AspNetCore.Components.EventCallback'
[CS0266] Cannot implicitly convert type 'SomeReason?' to 'SomeReason'. An explicit conversion exists (are you missing a cast?)
[CS1662] Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type
Run Code Online (Sandbox Code Playgroud)
解决方案如下:
在BetterInputSelect<TItem>:
// Was:
// [Parameter]
// public IEnumerable<TItem> Data { get; set; } = new List<TItem>();
[Parameter]
public IEnumerable<TItem?> Data { get; set; } = new List<TItem?>();
Run Code Online (Sandbox Code Playgroud)
我认为:
<BetterInputSelect
Data="@(Reasons as IEnumerable<SomeReason?>)"
TItem="SomeReason?"
@bind-Value="@Reason" />
Run Code Online (Sandbox Code Playgroud)
@Reason它在可为空和不可为空时起作用。不可为空的当然不需要强制转换和显式类型定义:
<BetterInputSelect
Data="@Reasons"
@bind-Value="@Reason" />
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2943 次 |
| 最近记录: |