2009-03-03 45 views
62

繼續從這個問題programmatically creating a drop down list我想我的列表也有幾個optgroup列表。目前這可能嗎?在下拉列表中支持optgroup .NET MVC?

我知道我需要將selectList傳遞給dropDownList,但不知道如何將文本,值,optgroup添加到selectList。

我想最終的結果產生:

<option value="">Please select</option> 
    <optgroup label="Option A"> 
    <option value="1">1</option> 
    <option value="2">2</option> 
    <option value="3">3</option> 
    <option value="4">4</option> 
    </optgroup> 
    <optgroup label="Option B"> 
    <option value="a">A</option> 
    <option value="b">B</option> 
    <option value="c">C</option> 
    </optgroup> 
</option> 
+3

現在內置到ASP.Net MVC版本5.2以上 - 請參閱我的回答 – 2014-09-11 09:50:21

回答

13

www.codeplex.com/aspnet通過代碼看,它不會出現,無論是選擇列表的,也不是DropDownList的擴展方法支持在選擇使用OPTGROUP的。看起來您需要編寫自己的擴展方法並擴展SelectListItem以包含分組或在標記中手動生成選擇。

25

我只寫做一個擴展,看到它:


using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Web.Routing; 

namespace System.Web.Mvc.Html 
{ 
    public static class GroupDropListExtensions 
    { 
     public static string GroupDropList(this HtmlHelper helper, string name, IEnumerable<GroupDropListItem> data, string SelectedValue, object htmlAttributes) 
     { 
      if (data == null && helper.ViewData != null) 
       data = helper.ViewData.Eval(name) as IEnumerable<GroupDropListItem>; 
      if (data == null) return string.Empty; 

      var select = new TagBuilder("select"); 

      if (htmlAttributes != null) 
       select.MergeAttributes(new RouteValueDictionary(htmlAttributes)); 

      select.GenerateId(name); 

      var optgroupHtml = new StringBuilder(); 
      var groups = data.ToList(); 
      foreach (var group in data) 
      { 
       var groupTag = new TagBuilder("optgroup"); 
       groupTag.Attributes.Add("label", helper.Encode(group.Name)); 
       var optHtml = new StringBuilder(); 
       foreach (var item in group.Items) 
       { 
        var option = new TagBuilder("option"); 
        option.Attributes.Add("value", helper.Encode(item.Value)); 
        if (SelectedValue != null && item.Value == SelectedValue) 
         option.Attributes.Add("selected", "selected"); 
        option.InnerHtml = helper.Encode(item.Text); 
        optHtml.AppendLine(option.ToString(TagRenderMode.Normal)); 
       } 
       groupTag.InnerHtml = optHtml.ToString(); 
       optgroupHtml.AppendLine(groupTag.ToString(TagRenderMode.Normal)); 
      } 
      select.InnerHtml = optgroupHtml.ToString(); 
      return select.ToString(TagRenderMode.Normal); 
     } 
} 

    public class GroupDropListItem 
    { 
     public string Name { get; set; } 
     public List<OptionItem> Items { get; set; } 
    } 

    public class OptionItem 
    { 
     public string Text { get; set; } 
     public string Value { get; set; } 
    } 
} 
+1

格式化代碼後,我注意到你有一個額外的`}`。你能檢查我沒有搞砸嗎?另外,如果使用空格而不是製表符,它可以提高可讀性。 – 2010-07-12 16:01:49

+0

失敗我正在使用您的擴展名,但選定的值沒有被保存在模型中..任何想法?謝謝 – beebul 2010-11-10 09:08:43

+4

請參閱http://stackoverflow.com/questions/4142986/optgroup-drop-down-support-in-mvc-problems-with-model-binding對代碼進行一些小改動,因爲我無法獲得它工作......謝謝。 – beebul 2010-11-10 14:54:55

91

我的擴展是更復雜一點,但它擁有所有重載爲原有的DropDownList了。

其實我已經創造了它特別能夠產生的DropDownList與團體和兩個被轉化加入選擇用jDoubleSelect

using System;using System.Collections;using System.Collections.Generic;using System.Globalization; using System.Linq;using System.Linq.Expressions;using System.Text; using System.Web;using System.Web.Mvc;using System.Web.Routing; 

public class GroupedSelectListItem : SelectListItem 
{ 
    public string GroupKey { get; set; } 
    public string GroupName { get; set; } 
} 

public static class HtmlHelpers 
{ 
    public static MvcHtmlString DropDownGroupList(this HtmlHelper htmlHelper, string name) 
    { 
     return DropDownListHelper(htmlHelper, name, null, null, null); 
    } 

    public static MvcHtmlString DropDownGroupList(this HtmlHelper htmlHelper, string name, IEnumerable<GroupedSelectListItem> selectList) 
    { 
     return DropDownListHelper(htmlHelper, name, selectList, null, null); 
    } 

    public static MvcHtmlString DropDownGroupList(this HtmlHelper htmlHelper, string name, string optionLabel) 
    { 
     return DropDownListHelper(htmlHelper, name, null, optionLabel, null); 
    } 

    public static MvcHtmlString DropDownGroupList(this HtmlHelper htmlHelper, string name, IEnumerable<GroupedSelectListItem> selectList, IDictionary<string, object> htmlAttributes) 
    { 
     return DropDownListHelper(htmlHelper, name, selectList, null, htmlAttributes); 
    } 

    public static MvcHtmlString DropDownGroupList(this HtmlHelper htmlHelper, string name, IEnumerable<GroupedSelectListItem> selectList, object htmlAttributes) 
    { 
     return DropDownListHelper(htmlHelper, name, selectList, null, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); 
    } 

    public static MvcHtmlString DropDownGroupList(this HtmlHelper htmlHelper, string name, IEnumerable<GroupedSelectListItem> selectList, string optionLabel) 
    { 
     return DropDownListHelper(htmlHelper, name, selectList, optionLabel, null); 
    } 

    public static MvcHtmlString DropDownGroupList(this HtmlHelper htmlHelper, string name, IEnumerable<GroupedSelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes) 
    { 
     return DropDownListHelper(htmlHelper, name, selectList, optionLabel, htmlAttributes); 
    } 

    public static MvcHtmlString DropDownGroupList(this HtmlHelper htmlHelper, string name, IEnumerable<GroupedSelectListItem> selectList, string optionLabel, object htmlAttributes) 
    { 
     return DropDownListHelper(htmlHelper, name, selectList, optionLabel, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); 
    } 

    public static MvcHtmlString DropDownGroupListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<GroupedSelectListItem> selectList) 
    { 
     return DropDownGroupListFor(htmlHelper, expression, selectList, null /* optionLabel */, null /* htmlAttributes */); 
    } 

    public static MvcHtmlString DropDownGroupListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<GroupedSelectListItem> selectList, object htmlAttributes) 
    { 
     return DropDownGroupListFor(htmlHelper, expression, selectList, null /* optionLabel */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); 
    } 

    public static MvcHtmlString DropDownGroupListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<GroupedSelectListItem> selectList, IDictionary<string, object> htmlAttributes) 
    { 
     return DropDownGroupListFor(htmlHelper, expression, selectList, null /* optionLabel */, htmlAttributes); 
    } 

    public static MvcHtmlString DropDownGroupListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<GroupedSelectListItem> selectList, string optionLabel) 
    { 
     return DropDownGroupListFor(htmlHelper, expression, selectList, optionLabel, null /* htmlAttributes */); 
    } 

    public static MvcHtmlString DropDownGroupListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<GroupedSelectListItem> selectList, string optionLabel, object htmlAttributes) 
    { 
     return DropDownGroupListFor(htmlHelper, expression, selectList, optionLabel, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); 
    } 

    public static MvcHtmlString DropDownGroupListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<GroupedSelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes) 
    { 
     if (expression == null) 
     { 
      throw new ArgumentNullException("expression"); 
     } 

     return DropDownListHelper(htmlHelper, ExpressionHelper.GetExpressionText(expression), selectList, optionLabel, htmlAttributes); 
    } 

    private static MvcHtmlString DropDownListHelper(HtmlHelper htmlHelper, string expression, IEnumerable<GroupedSelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes) 
    { 
     return SelectInternal(htmlHelper, optionLabel, expression, selectList, false /* allowMultiple */, htmlAttributes); 
    } 


    // Helper methods 

    private static IEnumerable<GroupedSelectListItem> GetSelectData(this HtmlHelper htmlHelper, string name) 
    { 
     object o = null; 
     if (htmlHelper.ViewData != null) 
     { 
      o = htmlHelper.ViewData.Eval(name); 
     } 
     if (o == null) 
     { 
      throw new InvalidOperationException(
       String.Format(
        CultureInfo.CurrentCulture, 
        "Missing Select Data")); 
     } 
     var selectList = o as IEnumerable<GroupedSelectListItem>; 
     if (selectList == null) 
     { 
      throw new InvalidOperationException(
       String.Format(
        CultureInfo.CurrentCulture, 
        "Wrong Select DataType")); 
     } 
     return selectList; 
    } 

    internal static string ListItemToOption(GroupedSelectListItem item) 
    { 
     var builder = new TagBuilder("option") 
     { 
      InnerHtml = HttpUtility.HtmlEncode(item.Text) 
     }; 
     if (item.Value != null) 
     { 
      builder.Attributes["value"] = item.Value; 
     } 
     if (item.Selected) 
     { 
      builder.Attributes["selected"] = "selected"; 
     } 
     return builder.ToString(TagRenderMode.Normal); 
    } 

    private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, string optionLabel, string name, IEnumerable<GroupedSelectListItem> selectList, bool allowMultiple, IDictionary<string, object> htmlAttributes) 
    { 
     name = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name); 
     if (String.IsNullOrEmpty(name)) 
     { 
      throw new ArgumentException("Null Or Empty", "name"); 
     } 

     bool usedViewData = false; 

     // If we got a null selectList, try to use ViewData to get the list of items. 
     if (selectList == null) 
     { 
      selectList = htmlHelper.GetSelectData(name); 
      usedViewData = true; 
     } 

     object defaultValue = (allowMultiple) ? htmlHelper.GetModelStateValue(name, typeof(string[])) : htmlHelper.GetModelStateValue(name, typeof(string)); 

     // If we haven't already used ViewData to get the entire list of items then we need to 
     // use the ViewData-supplied value before using the parameter-supplied value. 
     if (!usedViewData) 
     { 
      if (defaultValue == null) 
      { 
       defaultValue = htmlHelper.ViewData.Eval(name); 
      } 
     } 

     if (defaultValue != null) 
     { 
      var defaultValues = (allowMultiple) ? defaultValue as IEnumerable : new[] { defaultValue }; 
      var values = from object value in defaultValues select Convert.ToString(value, CultureInfo.CurrentCulture); 
      var selectedValues = new HashSet<string>(values, StringComparer.OrdinalIgnoreCase); 
      var newSelectList = new List<GroupedSelectListItem>(); 

      foreach (var item in selectList) 
      { 
       item.Selected = (item.Value != null) ? selectedValues.Contains(item.Value) : selectedValues.Contains(item.Text); 
       newSelectList.Add(item); 
      } 
      selectList = newSelectList; 
     } 

     // Convert each ListItem to an <option> tag 
     var listItemBuilder = new StringBuilder(); 

     // Make optionLabel the first item that gets rendered. 
     if (optionLabel != null) 
     { 
      listItemBuilder.AppendLine(ListItemToOption(new GroupedSelectListItem { Text = optionLabel, Value = String.Empty, Selected = false })); 
     } 

     foreach (var group in selectList.GroupBy(i => i.GroupKey)) 
     { 
      string groupName = selectList.Where(i => i.GroupKey == group.Key).Select(it => it.GroupName).FirstOrDefault(); 
      listItemBuilder.AppendLine(string.Format("<optgroup label=\"{0}\" value=\"{1}\">", groupName, group.Key)); 
      foreach (GroupedSelectListItem item in group) 
      { 
       listItemBuilder.AppendLine(ListItemToOption(item)); 
      } 
      listItemBuilder.AppendLine("</optgroup>"); 
     } 

     var tagBuilder = new TagBuilder("select") 
     { 
      InnerHtml = listItemBuilder.ToString() 
     }; 
     tagBuilder.MergeAttributes(htmlAttributes); 
     tagBuilder.MergeAttribute("name", name, true /* replaceExisting */); 
     tagBuilder.GenerateId(name); 
     if (allowMultiple) 
     { 
      tagBuilder.MergeAttribute("multiple", "multiple"); 
     } 

     // If there are any errors for a named field, we add the css attribute. 
     ModelState modelState; 
     if (htmlHelper.ViewData.ModelState.TryGetValue(name, out modelState)) 
     { 
      if (modelState.Errors.Count > 0) 
      { 
       tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName); 
      } 
     } 

     return MvcHtmlString.Create(tagBuilder.ToString()); 
    } 

    internal static object GetModelStateValue(this HtmlHelper helper, string key, Type destinationType) 
    { 
     ModelState modelState; 
     if (helper.ViewData.ModelState.TryGetValue(key, out modelState)) 
     { 
      if (modelState.Value != null) 
      { 
       return modelState.Value.ConvertTo(destinationType, null /* culture */); 
      } 
     } 
     return null; 
    } 

} 
1

數據註解幫助客戶驗證缺失?

在回答上述Chrno愛的問題,增加了塞爾朱達的解決方案 - 在同一視圖中使用的下拉列表中的集合時Milimetric的修爲MVC3客戶端驗證屬性:

 public static MvcHtmlString DropDownGroupListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, 
                     Expression<Func<TModel, TProperty>> 
                      expression, 
                     IEnumerable<GroupedSelectListItem> 
                      selectList, string optionLabel, 
                     IDictionary<string, object> htmlAttributes) 
    { 
     if (expression == null) 
     { 
      throw new ArgumentNullException("expression"); 
     } 

     // fixing clientside validation attributes 
     // http://stackoverflow.com/questions/4799958/asp-net-mvc-3-unobtrusive-client-validation-does-not-work-with-drop-down-lists/8102022#8102022 
     var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); 
      var mergedAttributes = 
       htmlHelper.GetUnobtrusiveValidationAttributes(ExpressionHelper.GetExpressionText(expression), metadata); 

      if (htmlAttributes != null) 
      { 
       foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(htmlAttributes)) 
       { 
        object value = descriptor.GetValue(htmlAttributes); 
        mergedAttributes.Add(descriptor.Name, value); 
       } 
      } 

     //return DropDownListHelper(htmlHelper, ExpressionHelper.GetExpressionText(expression), selectList, optionLabel, htmlAttributes); 
     return DropDownListHelper(htmlHelper, ExpressionHelper.GetExpressionText(expression), selectList, optionLabel, mergedAttributes); 
    } 
0

在塞爾日·朱達answer,數據屬性,如data_valuename,不要以正確的格式data-valuename marging。

我更換代碼tagBuilder.MergeAttributes(htmlAttributes);SelectInternal方法本

foreach (var htmlAttribute in htmlAttributes) 
{ 
    tagBuilder.MergeAttribute(
     htmlAttribute.Key.Replace('_', '-'), 
     (string)htmlAttribute.Value 
    ); 
} 
1

塞爾朱的回答正是我一直在尋找。作爲難改VB程序員我把它移植到本次VB模塊:

'based on Serge Zab's answer on http://stackoverflow.com/questions/607188/support-for-optgroup-in-dropdownlist-net-mvc 

Imports System.Collections 
Imports System.Collections.Generic 
Imports System.Globalization 
Imports System.Linq 
Imports System.Linq.Expressions 
Imports System.Text 
Imports System.Web 
Imports System.Web.Mvc 
Imports System.Web.Routing 

Public Class GroupedSelectListItem 
    Inherits SelectListItem 
    Public Property GroupKey() As String 
     Get 
      Return m_GroupKey 
     End Get 
     Set(value As String) 
      m_GroupKey = Value 
     End Set 
    End Property 
    Private m_GroupKey As String 
    Public Property GroupName() As String 
     Get 
      Return m_GroupName 
     End Get 
     Set(value As String) 
      m_GroupName = Value 
     End Set 
    End Property 
    Private m_GroupName As String 
End Class 

Public Module HtmlHelpers 
    <System.Runtime.CompilerServices.Extension> _ 
    Public Function DropDownGroupList(htmlHelper As HtmlHelper, name As String) As MvcHtmlString 
     Return DropDownListHelper(htmlHelper, name, Nothing, Nothing, Nothing) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Public Function DropDownGroupList(htmlHelper As HtmlHelper, name As String, selectList As IEnumerable(Of GroupedSelectListItem)) As MvcHtmlString 
     Return DropDownListHelper(htmlHelper, name, selectList, Nothing, Nothing) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Public Function DropDownGroupList(htmlHelper As HtmlHelper, name As String, optionLabel As String) As MvcHtmlString 
     Return DropDownListHelper(htmlHelper, name, Nothing, optionLabel, Nothing) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Public Function DropDownGroupList(htmlHelper As HtmlHelper, name As String, selectList As IEnumerable(Of GroupedSelectListItem), htmlAttributes As IDictionary(Of String, Object)) As MvcHtmlString 
     Return DropDownListHelper(htmlHelper, name, selectList, Nothing, htmlAttributes) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Public Function DropDownGroupList(htmlHelper As HtmlHelper, name As String, selectList As IEnumerable(Of GroupedSelectListItem), htmlAttributes As Object) As MvcHtmlString 
     Return DropDownListHelper(htmlHelper, name, selectList, Nothing, New RouteValueDictionary(htmlAttributes)) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Public Function DropDownGroupList(htmlHelper As HtmlHelper, name As String, selectList As IEnumerable(Of GroupedSelectListItem), optionLabel As String) As MvcHtmlString 
     Return DropDownListHelper(htmlHelper, name, selectList, optionLabel, Nothing) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Public Function DropDownGroupList(htmlHelper As HtmlHelper, name As String, selectList As IEnumerable(Of GroupedSelectListItem), optionLabel As String, htmlAttributes As IDictionary(Of String, Object)) As MvcHtmlString 
     Return DropDownListHelper(htmlHelper, name, selectList, optionLabel, htmlAttributes) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Public Function DropDownGroupList(htmlHelper As HtmlHelper, name As String, selectList As IEnumerable(Of GroupedSelectListItem), optionLabel As String, htmlAttributes As Object) As MvcHtmlString 
     Return DropDownListHelper(htmlHelper, name, selectList, optionLabel, New RouteValueDictionary(htmlAttributes)) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Public Function DropDownGroupListFor(Of TModel, TProperty)(htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TProperty)), selectList As IEnumerable(Of GroupedSelectListItem)) As MvcHtmlString 
     ' optionLabel 
     ' htmlAttributes 
     Return DropDownGroupListFor(htmlHelper, expression, selectList, Nothing, Nothing) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Public Function DropDownGroupListFor(Of TModel, TProperty)(htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TProperty)), selectList As IEnumerable(Of GroupedSelectListItem), htmlAttributes As Object) As MvcHtmlString 
     ' optionLabel 
     Return DropDownGroupListFor(htmlHelper, expression, selectList, Nothing, New RouteValueDictionary(htmlAttributes)) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Public Function DropDownGroupListFor(Of TModel, TProperty)(htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TProperty)), selectList As IEnumerable(Of GroupedSelectListItem), htmlAttributes As IDictionary(Of String, Object)) As MvcHtmlString 
     ' optionLabel 
     Return DropDownGroupListFor(htmlHelper, expression, selectList, Nothing, htmlAttributes) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Public Function DropDownGroupListFor(Of TModel, TProperty)(htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TProperty)), selectList As IEnumerable(Of GroupedSelectListItem), optionLabel As String) As MvcHtmlString 
     ' htmlAttributes 
     Return DropDownGroupListFor(htmlHelper, expression, selectList, optionLabel, Nothing) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Public Function DropDownGroupListFor(Of TModel, TProperty)(htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TProperty)), selectList As IEnumerable(Of GroupedSelectListItem), optionLabel As String, htmlAttributes As Object) As MvcHtmlString 
     Return DropDownGroupListFor(htmlHelper, expression, selectList, optionLabel, New RouteValueDictionary(htmlAttributes)) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Public Function DropDownGroupListFor(Of TModel, TProperty)(htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TProperty)), selectList As IEnumerable(Of GroupedSelectListItem), optionLabel As String, htmlAttributes As IDictionary(Of String, Object)) As MvcHtmlString 
     If expression Is Nothing Then 
      Throw New ArgumentNullException("expression") 
     End If 

     Return DropDownListHelper(htmlHelper, ExpressionHelper.GetExpressionText(expression), selectList, optionLabel, htmlAttributes) 
    End Function 

    Private Function DropDownListHelper(htmlHelper As HtmlHelper, expression As String, selectList As IEnumerable(Of GroupedSelectListItem), optionLabel As String, htmlAttributes As IDictionary(Of String, Object)) As MvcHtmlString 
     ' allowMultiple 
     Return SelectInternal(htmlHelper, optionLabel, expression, selectList, False, htmlAttributes) 
    End Function 


    ' Helper methods 

    <System.Runtime.CompilerServices.Extension> _ 
    Private Function GetSelectData(htmlHelper As HtmlHelper, name As String) As IEnumerable(Of GroupedSelectListItem) 
     Dim o As Object = Nothing 
     If htmlHelper.ViewData IsNot Nothing Then 
      o = htmlHelper.ViewData.Eval(name) 
     End If 
     If o Is Nothing Then 
      Throw New InvalidOperationException([String].Format(CultureInfo.CurrentCulture, "Missing Select Data", name, "IEnumerable<GroupedSelectListItem>")) 
     End If 
     Dim selectList As IEnumerable(Of GroupedSelectListItem) = TryCast(o, IEnumerable(Of GroupedSelectListItem)) 
     If selectList Is Nothing Then 
      Throw New InvalidOperationException([String].Format(CultureInfo.CurrentCulture, "Wrong Select DataType", name, o.[GetType]().FullName, "IEnumerable<GroupedSelectListItem>")) 
     End If 
     Return selectList 
    End Function 

    Friend Function ListItemToOption(item As GroupedSelectListItem) As String 
     Dim builder As New TagBuilder("option") With { _ 
      .InnerHtml = HttpUtility.HtmlEncode(item.Text) _ 
     } 
     If item.Value IsNot Nothing Then 
      builder.Attributes("value") = item.Value 
     End If 
     If item.Selected Then 
      builder.Attributes("selected") = "selected" 
     End If 
     Return builder.ToString(TagRenderMode.Normal) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Private Function SelectInternal(htmlHelper__1 As HtmlHelper, optionLabel As String, name As String, selectList As IEnumerable(Of GroupedSelectListItem), allowMultiple As Boolean, htmlAttributes As IDictionary(Of String, Object)) As MvcHtmlString 
     name = htmlHelper__1.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name) 
     If [String].IsNullOrEmpty(name) Then 
      Throw New ArgumentException("Null Or Empty", "name") 
     End If 

     Dim usedViewData As Boolean = False 

     ' If we got a null selectList, try to use ViewData to get the list of items. 
     If selectList Is Nothing Then 
      selectList = htmlHelper__1.GetSelectData(name) 
      usedViewData = True 
     End If 

     Dim defaultValue As Object = If((allowMultiple), htmlHelper__1.GetModelStateValue(name, GetType(String())), htmlHelper__1.GetModelStateValue(name, GetType(String))) 

     ' If we haven't already used ViewData to get the entire list of items then we need to 
     ' use the ViewData-supplied value before using the parameter-supplied value. 
     If Not usedViewData Then 
      If defaultValue Is Nothing Then 
       defaultValue = htmlHelper__1.ViewData.Eval(name) 
      End If 
     End If 

     If defaultValue IsNot Nothing Then 
      Dim defaultValues As IEnumerable = If((allowMultiple), TryCast(defaultValue, IEnumerable), New String() {defaultValue}) 
      Dim values As IEnumerable(Of String) = From value In defaultValues Select (Convert.ToString(value, CultureInfo.CurrentCulture)) 
      Dim selectedValues As New HashSet(Of String)(values, StringComparer.OrdinalIgnoreCase) 
      Dim newSelectList As New List(Of GroupedSelectListItem)() 

      For Each item As GroupedSelectListItem In selectList 
       item.Selected = If((item.Value IsNot Nothing), selectedValues.Contains(item.Value), selectedValues.Contains(item.Text)) 
       newSelectList.Add(item) 
      Next 
      selectList = newSelectList 
     End If 

     ' Convert each ListItem to an <option> tag 
     Dim listItemBuilder As New StringBuilder() 

     ' Make optionLabel the first item that gets rendered. 
     If optionLabel IsNot Nothing Then 
      listItemBuilder.AppendLine(ListItemToOption(New GroupedSelectListItem() With { _ 
       .Text = optionLabel, _ 
       .Value = [String].Empty, _ 
       .Selected = False _ 
      })) 
     End If 

     For Each group As Object In selectList.GroupBy(Function(i) i.GroupKey) 
      Dim groupName As String = selectList.Where(Function(i) i.GroupKey = group.Key).[Select](Function(it) it.GroupName).FirstOrDefault() 
      listItemBuilder.AppendLine(String.Format("<optgroup label=""{0}"" value=""{1}"">", groupName, group.Key)) 
      For Each item As GroupedSelectListItem In group 
       listItemBuilder.AppendLine(ListItemToOption(item)) 
      Next 
      listItemBuilder.AppendLine("</optgroup>") 
     Next 

     Dim tagBuilder As New TagBuilder("select") With { _ 
      .InnerHtml = listItemBuilder.ToString() _ 
     } 
     TagBuilder.MergeAttributes(htmlAttributes) 
     ' replaceExisting 
     TagBuilder.MergeAttribute("name", name, True) 
     TagBuilder.GenerateId(name) 
     If allowMultiple Then 
      TagBuilder.MergeAttribute("multiple", "multiple") 
     End If 

     ' If there are any errors for a named field, we add the css attribute. 
     Dim modelState As ModelState = Nothing 
     If htmlHelper__1.ViewData.ModelState.TryGetValue(name, modelState) Then 
      If modelState.Errors.Count > 0 Then 
       TagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName) 
      End If 
     End If 

     Return MvcHtmlString.Create(TagBuilder.ToString()) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Friend Function GetModelStateValue(helper As HtmlHelper, key As String, destinationType As Type) As Object 
     Dim modelState As ModelState = Nothing 
     If helper.ViewData.ModelState.TryGetValue(key, modelState) Then 
      If modelState.Value IsNot Nothing Then 
       ' culture 
       Return modelState.Value.ConvertTo(destinationType, Nothing) 
      End If 
     End If 
     Return Nothing 
    End Function 

End Module 
1

我一直在努力@Serge朱解出來效果很好,但在遇到一些麻煩不顯眼的驗證,經過一番考察,我發現這個問題。

似乎如果希望jQuery驗證火是一些需要的屬性丟失掉的選擇元素,您只創建後您的TagBuilder

TagBuilder tagBuilder = new TagBuilder("select"); 

添加這些屬性

tagBuilder.MergeAttribute("data-val", "true",true); 
tagBuilder.MergeAttribute("data-val-required", "your validation message", true) 

和不顯眼的驗證應該會觸發。

0

只需使用Serge的擴展在同一表單上創建多個選擇列表的註釋即可。我在獲取第二個選擇列表來應用組時遇到了問題,並且當我檢查正在生成的html時,我意識到兩者都被賦予了相同的ID。要解決此問題,請進入serge的擴展中的SelectInternal函數,並註釋掉/刪除以下兩行:

tagBuilder.MergeAttribute(「name」,name,true/* replaceExisting * /); tagBuilder.GenerateId(name);

或者你可以只通過唯一的ID對每個(雖然DropDownGroupListFor不走「字符串名稱」參數,所以你必須要補充一點,不超載)

34

將其加入ASP.Net MVC版本5.2,現在內置。

Group property on SelectListItem允許您指定一組爲每個項目:

SelectList constructors還允許您提供包含的項目所提供的名單上的組標題字段的名稱。

HtmlHelper DropDownList和DropDownListFor方法現在基於項目列表中包含的組生成optgroup元素。

簡單!

0

我需要一個解決方案來處理optgroup的多選,並且我使用了Serge Zab解決方案。我只有兩條評論(太長的評論)。

  • 儘管他的索賠自己的解決方案不支持DropDownListFor的所有現有的過載,因爲它不支持MultiSelectList或的SelectList,oftenly在模型中使用。但是這並不難。

  • 他的解決方案並不適用於我的多重選擇來初始化模型中選定的/未選擇的項目:初始值不受影響。 我剛剛修改了以下方法:

    私有靜態MvcHtmlString DropDownListHelper(...) { 回報SelectInternal(的HtmlHelper,optionLabel,表達,選擇列表的,假的/ * *的AllowMultiple /,htmlAttributes); }

要這樣:

private static MvcHtmlString DropDownListHelper(HtmlHelper htmlHelper, string expression, IEnumerable<GroupedSelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes) 
{ 
    bool allowMultiple = htmlAttributes.ContainsKey("multiple"); 
    return SelectInternal(htmlHelper, optionLabel, expression, selectList, allowMultiple, htmlAttributes); 
} 

和它的工作如預期。 當然多個屬性必須定義: @ Html.DropDownGroupListFor(M => m.Selected,Model.Values,新的{多個= 「多個」})

由於塞爾他的回答。