4

我已经为 EditorFor 和 DisplayFor 辅助方法创建了几个 MVC 模板,以使用 Twitter Bootstrap 框架按照我想要的方式设置样式。我现在有一个适用于我需要的所有位的工作解决方案,但想概括我设置的一个部分以显示状态列表。我有一个州枚举(包含所有美国州的列表),我在用户地址的下拉列表中显示。我使用 [DataType] 属性让 MVC 使用我的 State.cshtml 模板。

[Required]
[Display(Name = "State")]
[DataType("State")]
public State State { get; set; }

所以它工作得很好,但我想改变它,以便我可以做一些类似 DataType("Enum") 或其他方式来为所有枚举通用地点击这个模板。

模板如下所示:

@using System
@using System.Linq
@using Beno.Web.Helpers
@using TC.Util

@model Beno.Model.Enums.State

<div class="control-group">
    @Html.LabelFor(m => m, new {@class = "control-label{0}".ApplyFormat(ViewData.ModelMetadata.IsRequired ? " required" : "")})
    <div class="controls">
        <div class="input-append">
            @Html.EnumDropDownListFor(m => m)
            <span class="add-on">@(new MvcHtmlString("{0}".ApplyFormat(ViewData.ModelMetadata.IsRequired ? " <i class=\"icon-star\"></i>" : "")))</span>
        </div>
        @Html.ValidationMessageFor(m => m, null, new {@class = "help-inline"})
    </div>
</div>

EnumDropDownListFor 是我之前发布的一个辅助方法,它通常适用于任何枚举。我不知道如何更改此模板以将通用枚举作为模型对象?

更新:为了完整起见,我列出了 EnumDropDownListFor 方法:

public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null) where TProperty : struct, IConvertible
{
    if (!typeof(TProperty).IsEnum)
        throw new ArgumentException("TProperty must be an enumerated type");

    var selectedValue = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).Model.ToString();
    var selectList = new SelectList(from value in EnumHelper.GetValues<TProperty>()
                                    select new SelectListItem
                                                {
                                                    Text = value.ToDescriptionString(),
                                                    Value = value.ToString()
                                                }, "Value", "Text", selectedValue);

    return htmlHelper.DropDownListFor(expression, selectList, htmlAttributes);
}

将模型类型更改为 Enum 会在调用辅助方法的那一行产生以下错误:

CS0453: The type 'System.Enum' must be a non-nullable value type in order to use it as parameter 'TProperty' in the generic type or method 'Beno.Web.Helpers.ControlHelper.EnumDropDownListFor<TModel,TProperty>(System.Web.Mvc.HtmlHelper<TModel>, System.Linq.Expressions.Expression<System.Func<TModel,TProperty>>, object)'

然后,如果我删除检查 TProperty 是否为枚举和约束的结构,我会在我试图获取枚举值的行上得到一个编译错误:

System.ArgumentException: Type 'Enum' is not an enum

我想知道是否不可能做我在这里尝试的事情。

4

4 回答 4

1

你可以只创建一个 EditorTemplateEnum.cshtml

您所要做的就是更改这一行:

@model Beno.Model.Enums.State

为了这 :

@model System.Enum

然后你就可以使用Enum它了。

问题:引擎无法推断项目的基类,因此不会为 TestEnum 分配 Enum 模板,因此您必须显式调用它:

@Html.EditorFor(model => model.EnumValue, "Enum") 
于 2013-01-21T21:23:32.113 回答
0

我也一直在努力实现这一目标。

您是否希望能够为所有模型中的所有 Enum 类型使用一个模板。这样,您在 EditorTemplates 文件夹中有一个枚举模板,允许您将它们显示为下拉列表。

我一直在关注这篇文章。http://blogs.msdn.com/b/stuartleeks/archive/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums.aspx

您遇到的问题是您的模板在 TModel 和 TProperty 中传递了 System.Enum 的类型

Expression<Func<TModel, TProperty>> expression

然后,当您执行以下操作时,TProperty 的类型为 System.Enum 而不是 Beno.Model.Enums.State

 EnumHelper.GetValues<TProperty>()

为了解决这个问题,我不会费心去看 TProperty,因为它没有给我正确的类型。

相反,我查看 metadata.ModelType。

ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

这给了我正确的类型,但你不能在 Covariance Derived 类中使用它们

EnumHelper.GetValue<metadata.ModelType> //This does not work.

所以我重写了正文以不使用任何泛型。

        public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
    {
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

        var values = Enum.GetValues(metadata.ModelType);

        List<SelectListItem> items = new List<SelectListItem>();

        foreach (var v in values)
        {
            items.Add(new SelectListItem
            {
                Text = Regex.Replace(v.ToString(), "([A-Z][a-z])", " $1").Trim(),
                Value = v.ToString(),
                Selected = v.Equals(metadata.Model)
            });
        }

        return htmlHelper.DropDownListFor(expression, items);

    }

您可能需要更改方法签名以包含您的 htmlattributes。

于 2013-04-24T09:27:55.943 回答
0

不确定我是否完全理解你的意思,但试试这个:

@Html.DropDownListFor(model => model.EnumName, new SelectList(Enum.GetValues(typeof(Namespace.Models.EnumName))))

EnumName = 您的情况。

我已经使用上面的方法将枚举放入使用 Twitter Bootstrap 的下拉列表中。

于 2013-01-21T23:59:29.730 回答
0

正如其他人所展示的那样,编写自定义助手是要走的路。这正是TwitterBootstrapMVC中所做的。在其他助手中,它有一个 helper DropDownListFromEnumFor(...),您可以像这样使用它:

@Html.Bootstrap().DropDownListFromEnumFor(m => m.SomeEnum)

或者

@Html.Bootstrap().DropDownListFromEnum("SomeEnum")

BMVC 很酷的一点是,您可以使用扩展方法自定义下拉菜单,其中一些用于常规 html,而另一些则特定于 Bootstrap。以下是其中一些:

@(f.ControlGroup().DropDownListFromEnumFor(m => m.SomeEnum)
    .Append("something")
    .AppendIcon("glyphicon glyphicon-chevron-right")
    .Class("cool-dd")
    .OptionLabel("-- Select --")
    .Tooltip("cool tooltip"))

哦,是的,上面的示例将生成完整的控制组 - 输入、标签和验证消息。


免责声明:我是 TwitterBootstrapMVC 的作者

于 2013-11-13T18:00:09.530 回答