2009-03-03 13 views
62

Fortsetzung dieser Frage programmatically creating a drop down list Ich möchte meine Liste mehrere optgroup-Listen zu haben. Ist das derzeit möglich?Unterstützung für optgroup in Dropdownliste .NET MVC?

Ich weiß, ich muss eine selectList zu einer DropDownList übergeben, aber nicht wissen, wie Text, Wert, OptGroup der SelectList hinzufügen.

mag ich das Endergebnis produzieren: auf www.codeplex.com/aspnet

<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

Jetzt in ASP.Net MVC Version 5.2 integriert - siehe meine Antwort unten –

Antwort

13

Blick durch den Code, scheint es nicht, dass weder die Select noch die Dropdownlist Erweiterung Verfahren die Verwendung von optgroup in einem ausgewählten unterstützt. Offenbar müssen Sie Ihre eigene Erweiterungsmethode schreiben und SelectListItem erweitern, um die Gruppierung zu enthalten oder die Auswahl manuell in Markup zu generieren.

25

Ich schreibe nur ein Erweiterungen dies tun, sehen sie:


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

Nach der Formatierung Ihres Codes, habe ich festgestellt, dass Sie eine zusätzliche '}' haben. Kannst du nachsehen, dass ich nichts kaputt gemacht habe? Außerdem wird die Lesbarkeit erheblich verbessert, wenn Sie Leerzeichen anstelle von Tabs verwenden. –

+0

Lostway Ich benutze Ihre Erweiterung aber der ausgewählte Wert wird nicht im Modell gespeichert .. irgendwelche Ideen? Danke – beebul

+4

Bitte beachten Sie http://stackoverflow.com/questions/4142986/optgroup-drop-down-support-in-mvc-problems-with-model-binding für eine kleine Änderung an Ihrem Code, wie ich es nicht bekommen konnte Arbeit ... Danke. – beebul

91

Meine Erweiterung ein wenig komplizierter, aber es hat alle Überlastungen wie original Dropdownlist hat.

Eigentlich habe ich erstellt es speziell der Lage sein, mit Gruppen zu erzeugen und Dropdownlist fehlt in zwei verbunden wählt mit Hilfe von 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; 
    } 

} 
+0

Ehrfürchtig, aber eine Frage: Ist diese Unterstützung für Datenanmerkungen Client-Validierung? –

+0

Große Lösung! – Christian13467

+0

Dies ist eine großartige Lösung! Vielen Dank! Direkt in meine MVC-App eingefügt. :) –

1

Daten Anmerkungen für die Client-Validierungen transformiert werden?

In Antwort auf Chrno Love obigen Frage, was zur Serge Zab-Lösung - Milimetric ist fix für MVC3 Clientside Validierungsattribute, wenn eine Sammlung von Dropdown-Listen in der gleichen Ansicht mit:

 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

Schön, funktioniert super, danke! – ManicBlowfish

0

In Serge Zab answer, Datenattribute , wie data_valuename, nicht in korrekter Form margieren data-valuename.

I ersetzt Code tagBuilder.MergeAttributes(htmlAttributes); in SelectInternal Verfahren zur dies

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

Serge Antwort Pisos war genau das, was ich suchte. Als eine Form Programmierer schwer VB ich portiert es auf diese VB-Modul:

'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

Ich habe @Serge Zab Lösung aus versucht, die gut funktioniert, wurde aber einige Schwierigkeiten mit der unaufdringlichen Validierung hat, nach einiger Inspektion fand ich das Problem .

Es scheint einige erforderliche Attribute das select-Element fehlt, aus zu sein, wenn Sie die Jquery Validierung feuern wollen, nur, nachdem Sie Ihre TagBuilder erstellen

TagBuilder tagBuilder = new TagBuilder("select"); 

Fügen Sie diese Attribute

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

und die unauffällige Validierung sollte auslösen.

0

Nur ein Hinweis zur Verwendung von Serges Erweiterung, um mehr als eine Auswahlliste auf demselben Formular zu erstellen.Ich hatte Probleme, die zweite Auswahlliste zu bekommen, um die Gruppen anzuwenden, und als ich den erzeugten HTML prüfte, erkannte ich, dass beide die gleiche Identifikation erhalten hatten. Um dies zu beheben, gehen Sie in die Funktion SelectInternal in der Erweiterung von serge und kommentieren/löschen Sie die folgenden zwei Zeilen:

tagBuilder.MergeAttribute ("name", name, true/* replaceExisting * /); tagBuilder.GenerateId (Name);

Alternativ können Sie nur eindeutige ID des passieren jeweils (obwohl die DropDownGroupListFor nicht nehmen Sie die ‚string name‘ Parameter, so dass Sie eine Überlastung hinzufügen müssen werden, der Fall ist)

34

Dies wurde auf ASP.Net hinzugefügt MVC bei Version 5.2 und ist jetzt eingebaut.

Die Group property on SelectListItem können Sie eine Gruppe für jedes Element angeben:

New SelectList constructors erlauben auch Sie den Namen des Feldes zur Verfügung zu stellen, die den Gruppentitel auf der mitgelieferten Liste der Elemente enthält.

Die HtmlHelper DropDownList- und DropDownListFor-Methoden generieren jetzt optgroup-Elemente basierend auf den Gruppen, die in der Liste der Elemente enthalten sind.

Einfach!

+3

Ja! Und ein Beispiel hier: http://qiita.com/rryu/items/0fdfde55a62a44f0add0 var items = new List (); var group1 = neu SelectListGroup() {Name = "Gruppe 1"}; items.Add (neues SelectListItem() {Text = "Item1", Group = group1}); und @ Html.DropDownList ("Select", Artikel) – clement

+0

das funktioniert sehr gut. –

+0

Ausgezeichnete Antwort, glücklich zu sehen, dass diese Funktionalität jetzt enthalten ist! – Dal

0

Ich brauchte eine Lösung, um eine Mehrfachauswahl mit optgroup zu handhaben, und ich verwendete Serge Zab Lösung. Ich habe nur zwei Kommentare (zu lang für einen Kommentar).

  • Trotz seiner Forderungen hat seine Lösung nicht alle vorhandenen Überlastungen von DropDownListFor unterstützen, da es oftenly nicht MultiSelectList oder Select unterstützen, in Modellen verwendet. Aber das ist nicht schwer hinzuzufügen.

  • Seine Lösung funktionierte bei mir nicht für die Mehrfachselektion, um ausgewählte/nicht ausgewählte Elemente vom Modell zu initialisieren: die Anfangswerte waren nicht betroffen. Ich habe modifiziert nur die folgende Methode:

    private static MvcHtmlString DropDownListHelper (...) { return SelectInternal (Htmlhelper, option, Ausdruck, select false/* allowMultiple * /, Htmlattributes); }

Um dies:

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); 
} 

Und es funktionierte wie erwartet. Natürlich muss das mehr Attribut definiert werden: @ Html.DropDownGroupListFor (m => m.Selected, Model.Values, neuer {multiple = "multiple"})

Dank Serge für seine Antwort.

Verwandte Themen