自定义验证服务器&客户端用于填充枚举类型的下拉列表

时间:2012-03-24 14:01:19

标签: asp.net-mvc

假设你有一个这样的枚举:

public enum ColorsEnum
{
    Undefined,
    Blue,
    Red,
    Green
}

这样的模型:

public class Foo
{
    public ColorsEnum PreferedColor { get; set; }
}

有这样的观点:

@model WebUI.Models.Foo

@using (Html.BeginForm())
{
    @Html.LabelFor(m => m.PreferedColor)
    @Html.DropDownListForEnum(m => m.PreferedColor)
    <input type="submit">
}

这是DropdownListForEnum的帮助:

    public static IHtmlString DropDownListForEnum<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
                                                                     Expression<Func<TModel, TProperty>> expression)
    {
        var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        if (metaData.ModelType.IsEnum)
        {
            var names = Enum.GetNames(metaData.ModelType);
            var translatedNames = GetTranslatedNames(metaData.ModelType);

            var query = from p in names
                        select new SelectListItem
                                   {
                                       Text = translatedNames.ContainsKey(p) ? translatedNames[p] : p,
                                       Value = p,
                                       Selected = false
                                   };

            return htmlHelper.DropDownList(metaData.PropertyName, query.ToList());
        }
        else
        {
            throw new ApplicationException(
                "The DropDownListForEnum helper function must be used with an enum property");
        }
    }

我的问题:如何执行验证(客户端和服务器端)以确保用户选择有效的颜色?验证过程应拒绝“未定义”颜色。

感谢。

2 个答案:

答案 0 :(得分:0)

如果您计划与DropDownListForEnum一起使用的每个枚举的第一个值始终是验证者应拒绝的“默认”选项,您可以考虑使用optionLabel DropDownList参数1}}。

弹出query中的第一个元素,并将该字符串作为DropDownList中的第三个参数传递。

return htmlHelper.DropDownList(metaData.PropertyName, query.ToList(),
    /* some string containing default value extracted from your enum */);

这样,使用DropDownListForEnum创建的所有DDL都将使用枚举的第一个值作为“默认”值,而您要验证的所有操作都是添加[Required]数据注释到PreferredColor

或者,您可以从枚举中删除Default选项,并允许您的HtmlHelper(或创建一个新选项)获取第三个参数,即包含optionLabel的字符串,您将传递给{ {1}}。

无论哪种方式,我们的想法是利用DropDownList作为验证者为您完成所有工作。

答案 1 :(得分:0)

我会在视图模型上使用可空的枚举和必需属性:

public class MyViewModel
{
    [Required]
    public ColorsEnum? PreferedColor { get; set; }
}

因此,您可以从枚举定义中删除Undefined值:

public enum ColorsEnum
{
    Blue,
    Red,
    Green
}

然后稍微修改你的助手:

public static class HtmlExtensions
{
    public static IHtmlString DropDownListForEnum<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression
    )
    {
        var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        var enumType = Nullable.GetUnderlyingType(metaData.ModelType);
        if (enumType == null || !enumType.IsEnum)
        {
            throw new ApplicationException(
                "The DropDownListForEnum helper function must be used with a nullable enum property"
            );
        }

        var names = Enum.GetNames(enumType);
        var translatedNames = GetTranslatedNames(metaData.ModelType);

        var query = 
            from p in names
            select new SelectListItem
            {
                Text = translatedNames.ContainsKey(p) ? translatedNames[p] : p,
                Value = p,
                Selected = false
            };
        return htmlHelper.DropDownList(
            metaData.PropertyName, 
            query.ToList(), 
            "-- Select a color --"
        );
    }
}

然后有一个简单的控制器来测试:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel());
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return View(model);
    }
}

和相应的观点:

@model MyViewModel

<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>

@using (Html.BeginForm())
{
    @Html.LabelFor(m => m.PreferedColor)
    @Html.DropDownListForEnum(m => m.PreferedColor)
    <input type="submit" />
}