我正在为我的应用编写一个可重复使用的视图。它使用通用的ViewModel DynSingleView<T>
;您插入对象类型,视图将生成属性UI组件以更新它们。它有点复杂,因为它不是实际包含要编辑的数据的ViewModel,而是包含DisplayValue
个对象的列表,每个对象代表一个属性(并包含元数据)。可以使用这些(通过PropertyInfo.GetValue()方法)从通用对象中检索值。
主要障碍是使用Html.EditorFor
方法。使用它将为我在阅读和写入房产方面节省大量的工作。但是,要使用它,我需要为它提供一个表示简单属性/字段访问的lambda表达式(即model => model.Item.Property
)。
我在ViewModel中使用以下方法生成表达式:
/// <summary>
/// Given a property, returns a lambda expression that returns that property.
/// </summary>
/// <param name="dv">DisplayValue object, which is the property</param>
/// <returns></returns>
public Expression<Func<DynSingleView<T>, TType>> GetExpression<TType>(DisplayValue dv)
{
var param = Expression.Parameter(typeof(DynSingleView<T>));
var instance = Expression.Property(param, nameof(DynSingleView<T>.Item));
var propertyCall = Expression.Property(instance, dv.PropertyName);
var lambda = Expression.Lambda<Func<DynSingleView<T>, TType>>(propertyCall, param);
return lambda;
}
当涉及枚举时,这会生成所需的lambda完全除外。当我检索枚举属性时,我在lambda声明行上收到以下错误:Expression of type MyProject.Model.Enums.MyEnum cannot be used for return type 'System.Enum'.
我甚至无法将其转换为lambda中的对象,因为lambda需要是一个简单的属性访问。
@Jose帮助组合了一个linq表达式,该表达式“欺骗”了lambda表达式而没有出现错误并返回类型'System.Enum'(使用该类型作为'Html.EnumDropDownListFor'的泛型参数),但是在Return type 'System.Enum' is not supported.'
行生成错误:Html.EnumDropDownListFor
。
这是通用视图中的表格:
<table border="1">
@{
foreach (var dv in Model.DisplayValues)
{
@:<tr><td>@dv.PropertyDisplayName</td><td>
switch (dv.Type)
{
case DisplayValueType.Decimal:
@Html.EditorFor(Model.GetExpression<decimal>(dv));
break;
case DisplayValueType.String:
case DisplayValueType.Other:
@Html.EditorFor(Model.GetExpression<object>(dv));
break;
//this is where I'm having trouble
case DisplayValueType.PickList:
@Html.EnumDropDownListFor(Model.GetExpression<object>(dv));
break;
}
@:</td></tr>
}
}
<tr></tr>
</table>
似乎我能够完成这项工作的唯一方法是指定确切的枚举类型,这使得整个工作完全没用。
请帮忙!
答案 0 :(得分:2)
我90%肯定你想要的是这个
foreach (var dv in Model.DisplayValues)
{
@:<tr>
<td>@dv.PropertyDisplayName</td>
<td>
switch (dv.Type)
{
case DisplayValueType.Decimal:
case DisplayValueType.String:
case DisplayValueType.Other:
@Html.Editor("Item."+dv.PropertyName);
case DisplayValueType.PickList:
@Html.DropDownList("Item."+dv.PropertyName,EnumHelper.GetSelectList(Model.Item.GetType().GetProperty(dv.PropertyName).PropertyType));
break;
}
@:
</td>
</tr>
}
答案 1 :(得分:0)
如果您想进行静态类型检查,则必须将每个enum
视为一个单独的类型(就像您执行Decimal
和String
)并给他们自己的案例相同,除非对于类型。
答案 2 :(得分:0)
您插入对象类型,视图将生成属性UI组件以更新它们。
您可以使用EditorTemplates执行此操作。为要编辑的每种类型创建EditorTemplate。 MVC在运行时解析这些,因此您可以有10种不同的类型,它们将为每个类型生成不同的HTML:
动作
List<object> model = new List<object>
{
"hello world",
123,
true,
};
return View(model);
View在运行时选择EditorTemplate
@model List<object>
@for (int i = 0; i < Model.Count; i++)
{
@Html.EditorFor(m => m[i]) // textbox, numerical textbox, then checkbox
}
〜/查看/共享/ EditorTemplates / String.cshtml
@model string
@Html.TextBoxFor(m => m)
等等。这是一个极端的例子 - 通常你会使用基类而不是对象。
回发后可能会出现问题,默认情况下MVC模型活页夹可能无法识别不同的类型。您可以通过编写自定义模型绑定器来解决这个问题。
答案 3 :(得分:-1)
您可以将属性转换为TType,然后将其用作lambda的参数。
var convert = Expression.Convert(propertyCall, typeof(TType));
var lambda = Expression.Lambda<Func<DynSingleView<T>, TType>>(convert, param);