【发布时间】:2020-11-20 11:15:18
【问题描述】:
我正在尝试使用 Blazor 构建一个通用表单组件。目前,除了枚举选择之外,所有其他输入类型都在工作。我认为这是因为编译器在尝试添加表达式和回调函数时不知道具体的枚举类型:
public partial class GenericForm<ViewModel> : ComponentBase where ViewModel : new()
{
[Parameter]
public ViewModel Model { get; set; }
public readonly PropertyInfo[] Properties = typeof(ViewModel).GetProperties();
[Parameter] public EventCallback<ViewModel> OnValidSubmit { get; set; }
protected override async Task OnInitializedAsync()
{
if (Model == null)
{
Model = new ViewModel();
}
await base.OnInitializedAsync();
}
public RenderFragment CreateComponent(PropertyInfo property) => builder =>
{
var typeCode = Type.GetTypeCode(property.PropertyType);
if (property.PropertyType.IsEnum)
{
BuildEnumComponent(builder,property);
}
else
{
switch (typeCode)
{
case TypeCode.Int32:
BuildComponent<double>(property, builder, typeof(InputNumber<double>));
break;
case TypeCode.Int64:
BuildComponent<long>(property, builder, typeof(InputNumber<long>));
break;
case TypeCode.Int16:
BuildComponent<int>(property, builder, typeof(InputNumber<int>));
break;
case TypeCode.Decimal:
BuildComponent<decimal>(property, builder, typeof(InputNumber<decimal>));
break;
case TypeCode.String:
BuildComponent<string>(property, builder, typeof(InputText));
break;
case TypeCode.Boolean:
BuildComponent<bool>(property, builder, typeof(InputCheckbox));
break;
case TypeCode.DateTime:
BuildComponent<DateTime>(property, builder, typeof(InputDate<DateTime>));
break;
default:
Console.WriteLine("Unknown property type");
break;
}
}
};
private void BuildEnumComponent(RenderTreeBuilder builder,PropertyInfo property)
{
Guid id = Guid.NewGuid();
builder.AddMarkupContent(1, $"<label for=\"{id}\">{property.Name}</label>");
builder.OpenElement(2, "select");
builder.AddAttribute(3, "id", id.ToString());
builder.AddAttribute(4, "Value", Enum.GetValues(property.PropertyType).GetValue(0));
builder.AddAttribute(5, "ValueChanged", CreateCallback<Enum>(property));
builder.AddAttribute(6, "ValueExpression", CreateExpression<Enum>(property));
foreach (var value in Enum.GetValues(property.PropertyType))
{
builder.OpenElement(1, "option");
builder.AddAttribute(2, "value", value.ToString());
builder.CloseElement();
}
builder.CloseElement();
}
private void BuildComponent<PropertyType>(PropertyInfo property, RenderTreeBuilder builder, Type inputType)
{
var propertyValue = property.GetValue(Model);
var id = Guid.NewGuid();
builder.AddMarkupContent(0, $"<label for=\"{id}\">{property.Name}</label>");
builder.OpenComponent(1, inputType);
builder.AddAttribute(2, "id", id.ToString());
builder.AddAttribute(3, "Value", propertyValue);
builder.AddAttribute(5, "ValueChanged", CreateCallback<PropertyType>(property));
builder.AddAttribute(6, "ValueExpression", CreateExpression<PropertyType>(property));
builder.CloseComponent();
}
private EventCallback<PropertyType> CreateCallback<PropertyType>(PropertyInfo property)
{
return RuntimeHelpers.TypeCheck(EventCallback.Factory.Create(this, EventCallback.Factory.CreateInferred(this, __value => property.SetValue(Model, __value), (PropertyType)property.GetValue(Model))));
}
private Expression<Func<PropertyType>> CreateExpression<PropertyType>(PropertyInfo property)
{
var constant = Expression.Constant(Model, Model.GetType());
var exp = Expression.Property(constant, property.Name);
return Expression.Lambda<Func<PropertyType>>(exp);
}
}
它在这一行崩溃:return Expression.Lambda<Func<PropertyType>>(exp); 并出现此错误:System.ArgumentException: 'Expression of type 'Backender.Core.Common.Enums.EntityFieldType' cannot be used for return type 'System.Enum''。 EntityFieldType 也是一个枚举。
有什么建议吗?
【问题讨论】:
标签: c# .net-core reflection blazor blazor-server-side