Blazor中基于泛型列表泛型对象绑定原生输入组件生成表单的问题
可以实现,你遇到的空引用异常和绑定失败问题来自两个核心原因:类型不匹配、循环变量绑定的表达式树解析问题,按下面的方法调整即可。
- 第一,Blazor原生输入组件对绑定值的类型有强要求:比如
InputText只接受string类型的Value参数,你直接绑定Field<object>的Value(object类型),Blazor生成绑定逻辑时无法正确处理类型转换和表达式树,就会抛出无明确堆栈的空引用异常。 - 第二,直接在循环中绑定集合元素的属性时,手动构造
ValueExpression容易出现路径解析错误,导致内部校验逻辑抛空。
方案1:手动补全绑定三参数(适合类型较少的场景)
不用泛型组件,直接在绑定时显式指定Value、ValueChanged、ValueExpression三个参数,强制做类型转换:
foreach(Field<object> field in model.FieldList) { if (field.Info.DataTypeCode == "text") { <InputText Value="@(field.Value as string)" ValueChanged="@((string val) => field.Value = val)" ValueExpression="@(() => (string)field.Value)" /> } // 其他类型同理,比如数字类型 else if (field.Info.DataTypeCode == "number") { <InputNumber Value="@(field.Value as int?)" ValueChanged="@((int? val) => field.Value = val)" ValueExpression="@(() => (int?)field.Value)" /> } }
注意:需要提前保证
field.Info已经完成赋值,没有null值,否则访问DataTypeCode本身就会触发空引用异常。
方案2:泛型子组件+DynamicComponent(适合类型多、可扩展性要求高的场景)
先创建泛型字段渲染组件FormFieldRenderer.razor:
@typeparam TValue @switch (DataTypeCode) { case "text": <InputText @bind-Value="Value" /> break; case "number": <InputNumber @bind-Value="Value" /> break; case "datetime": <InputDate @bind-Value="Value" /> break; // 扩展其他类型组件 } @code { [Parameter] public TValue Value { get; set; } [Parameter] public EventCallback<TValue> ValueChanged { get; set; } [Parameter] public string DataTypeCode { get; set; } }
父组件中使用DynamicComponent动态构造对应类型的渲染组件:
@foreach (var field in model.FieldList) { <DynamicComponent Type="@typeof(FormFieldRenderer<>).MakeGenericType(field.Info.DataType)" Parameters="@new Dictionary<string, object> { { nameof(FormFieldRenderer<object>.Value), field.Value }, { nameof(FormFieldRenderer<object>.ValueChanged), EventCallback.Factory.Create(this, (object val) => field.Value = val) }, { nameof(FormFieldRenderer<object>.DataTypeCode), field.Info.DataTypeCode } }" /> }
这个方案会自动处理类型匹配和表达式生成,不需要手动写转换逻辑,扩展性更强。
内容的提问来源于stack exchange,提问作者Rutger
相关产品推荐
相关产品推荐

