MVC3:让帮助程序知道模型属性在图形中的位置



我的一个页面有一个相当复杂的模型;它由几个嵌套的模型对象组成。 在将子对象与子集合一起使用的一个部分中,我使用 EditorFor 帮助程序,如下所示:

@Html.EditorFor(m => m.CAS.LERoles[i].LE, "TinyText")

,我最终会得到这样的东西:

<input id="CAS_LERoles_0__LE" class="tinyText" type="text" value="0" name="CAS.LERoles[0].LE" data-val-required="The Legal Entity field is required." data-val-number="The field Legal Entity must be a number." data-val="true">

。这太好了。 但是,我编写了自己的帮助程序将枚举转换为选择列表,如下所示:

public static HtmlString EnumSelectListFor<TModel, TProperty>(
    this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TProperty>> forExpression,
    object htmlAttributes,
    bool blankFirstLine)
    where TModel : class
    where TProperty : struct
{
    //MS, it its infinite wisdom, does not allow enums as a generic constraint, so we have to check here.
    if (!typeof(TProperty).IsEnum) throw new ArgumentException("This helper method requires the specified model property to be an enum type.");
    //initialize values
    var metaData = ModelMetadata.FromLambdaExpression(forExpression, htmlHelper.ViewData);
    var propertyName = metaData.PropertyName;
    var propertyValue = htmlHelper.ViewData.Eval(propertyName).ToStringOrEmpty();
    //build the select tag
    var returnText = string.Format("<select id="{0}" name="{0}"", HttpUtility.HtmlEncode(propertyName));
    if (htmlAttributes != null)
    {
        foreach (var kvp in htmlAttributes.GetType().GetProperties()
            .ToDictionary(p => p.Name, p => p.GetValue(htmlAttributes, null)))
        {
            returnText += string.Format(" {0}="{1}"", HttpUtility.HtmlEncode(kvp.Key),
                HttpUtility.HtmlEncode(kvp.Value.ToStringOrEmpty()));
        }
    }
    returnText += ">n";
    if (blankFirstLine)
    {
        returnText += "<option value=""></option>";
    }
    //build the options tags
    foreach (var enumName in Enum.GetNames(typeof(TProperty)))
    {
        var idValue = ((int)Enum.Parse(typeof(TProperty), enumName, true)).ToString();
        var displayValue = enumName;
        // get the corresponding enum field using reflection
        var field = typeof(TProperty).GetField(enumName);
        var display = ((DisplayAttribute[])field.GetCustomAttributes(typeof(DisplayAttribute), false)).FirstOrDefault();
        var titleValue = string.Empty;
        if (display != null)
        {
            // The enum field is decorated with the DisplayAttribute =>
            // use its value
            displayValue = display.Name;
            titleValue = display.Description.ToStringOrEmpty();
        }
        returnText += string.Format("t<option value="{0}" title="{1}"",
            HttpUtility.HtmlEncode(idValue), HttpUtility.HtmlEncode(titleValue));
        if (enumName == propertyValue)
        {
            returnText += " selected="selected"";
        }
        returnText += string.Format(">{0}</option>n", HttpUtility.HtmlEncode(displayValue));
    }
    //close the select tag
    returnText += "</select>n";
    return new HtmlString(returnText);
}

当我在我的页面中使用它时,如下所示:

@Html.EnumSelectListFor(m => m.CAS.LERoles[i].APMasterRole)

我最终得到这个:

<select name="APMasterRole" id="APMasterRole">
(stuff)
</select>

回想起来,我想我以为这会被适当地翻译,现在我意识到我有点天真。 我真的希望 MVC 框架中内置了一种机制,我可以用来生成正确的名称和 id;否则,这看起来像一个反射迷宫。

所以问题是,是否有一种机制可用于为这样的复杂模型对象创建名称和 id 字符串? 如果是这样,它将如何使用? 如果没有,是否有一种相对简单的方法来生成名称和 id,以便表单数据可以绑定回对象模型?

谢谢!

我真的希望MVC框架中内置了一种机制 我可以用来生成正确的名称和 id;否则这个 看起来像一个反射迷宫。

当然有这样的机制。您认为内置助手是如何做到的?你没读过 ASP.NET MVC框架的源代码吗?或者使用反射器什么的?

string name = ExpressionHelper.GetExpressionText(forExpression);
var ti = htmlHelper.ViewContext.ViewData.TemplateInfo;
string fullHtmlFieldName = ti.GetFullHtmlFieldName(name);
string id = ti.GetFullHtmlFieldId(fullHtmlFieldName);
// Now go ahead and use fullHtmlFieldName and id
var returnText = string.Format(
    "<select id="{0}" name="{1}"", 
    id, 
    fullHtmlFieldName
);

啊,在我忘记之前:请使用TagBuilder生成 DOM 元素,例如 <select> 而不是这种可怕的字符串连接,它不能正确编码任何东西。更不用说循环内字符串上的+=运算符了。字符串是不可变的,这会消耗您的内存分配!至少使用StringBuilder.

最新更新