2011-10-03 54 views
0

我跟随this blog可以从ViewModels中需要的几个枚举创建DropDownLists。如何添加 - 从DropDownList中选择一些东西 - 从枚举中创建

到目前为止,我的代码看起来像这样:

public static class HtmlDropDownExtensions 
{ 
    private static readonly SelectListItem [] SingleEmptyItem = new[]{new SelectListItem{Text = string.Empty, Value = string.Empty}}; 

public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper, string modelPropertyName, TEnum selectedValue) 
{ 
    Type baseEnumType = Enum.GetUnderlyingType(typeof(TEnum)); 
    IEnumerable<TEnum> values = Enum.GetValues(typeof (TEnum)).Cast<TEnum>(); 
    IEnumerable<SelectListItem> items = GetSelectListItems(values, selectedValue, baseEnumType); 

    return htmlHelper.DropDownList(modelPropertyName, items); 
} 

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

    Type baseEnumType = Enum.GetUnderlyingType(enumType); 
    IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>(); 
    IEnumerable<SelectListItem> items = GetSelectListItems(values, metadata.Model, baseEnumType); 

    if (metadata.IsNullableValueType) 
     items = SingleEmptyItem.Concat(items); 

    return htmlHelper.DropDownListFor(expression, items); 
} 

private static Type GetNonNullableModelType(ModelMetadata modelMetadata) 
{ 
    Type realModelType = modelMetadata.ModelType; 

    Type underlyingType = Nullable.GetUnderlyingType(realModelType); 
    if(underlyingType != null) 
     realModelType = underlyingType; 

    return realModelType; 
} 

private static IEnumerable<SelectListItem> GetSelectListItems<TEnum>(IEnumerable<TEnum> values, object selectedValue, Type underlyingType) 
{ 
    return from value in values 
      select new SelectListItem 
      { 
       Text = value.ToString(), 
       Value = Convert.ChangeType(value, underlyingType).ToString(), 
       Selected = (value.Equals(selectedValue)) 
      }; 
    } 
} 

现在我需要的是能够有一个提示用户的第一选择,以选择一个选项,是因为空白或不选择什么字段是必需的,并且不能有任何默认值。

更新: 我在想,也许“EnumDropDownList”的方法也可以在创建的DropDownList并返回字符串前加空SelectListItem。我还没有尝试过,但我认为MVC工程将尝试将其绑定到ViewModel时会出现错误,因为无法将该值解析到ViewModel的枚举属性中。

感谢您的帮助。

+0

在列表的开始处插入默认项:dropdownlist.Insert(0,defaultItem); – MrFox

+0

@MFFOX:对不起,纠正我,如果我错了,但我认为这只会在Web窗体解决方案,而不是在MVC之一。 –

回答

0

其实你已经拥有了一切实现的:

if (metadata.IsNullableValueType) 
    items = SingleEmptyItem.Concat(items); 

如果模型的属性是Nullable<YourEnum>类型的,这个代码将在DropDownList中的开头添加默认项。

但是,如果属性不允许空值,则不会呈现默认值。这是正确的行为 - 应该要求用户输入内容并且不应该看到任何默认项目。

如果要更改默认值的文本,去SingleEmptyItem定义:

private static readonly SelectListItem [] SingleEmptyItem = new[]{new SelectListItem{Text = "Your text here", Value = string.Empty}}; 
+0

所以,如果我正确理解我将不得不做的是使所有我的枚举属性可以为空,并创建一些自定义DataAnotaion必需属性来验证该属性不为空。对?这是这个要求的最佳解决方案还是我让事情变得复杂?非常感谢你的想法。 –

+0

如果您不想让枚举属性接受空值,那么为什么要将空值添加到相应的下拉列表中?就我个人而言,我没有看到任何理由。但是,如果您仍想在下拉列表中选择默认值“--Select--”,但需要禁用空值,则可以将枚举属性设置为空,并使用“System.ComponentModel.DataAnnotations.RequiredAttribute'属性对其进行装饰。由于您的默认值为“”,因此此属性将导致验证失败,并且用户需要从下拉列表中选择任何内容。希望能帮助到你! – Andrei

+0

请允许我解释一下。我正在构建一个入口表单,其中有许多由枚举形成的下拉字段。例如,一个字段是出生国家。由于用户不仅可以选择他的出生国,而且还可以发送预先选择的数据,这样会使我们的数据不正确,因此用户不能提交表格。这就是为什么我问这个问题还是我过分复杂的问题? –