Поддержка optgroup в раскрывающемся списке .NET MVC?
-
03-07-2019 - |
Вопрос
Продолжая этот вопрос программное создание раскрывающегося списка Я бы хотел, чтобы в моем списке было несколько optgroup
списки тоже.Возможно ли это в настоящее время?
Я знаю, что мне нужно передать 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>
Решение
Просматривая код на www.codeplex.com/aspnet, похоже, что ни метод расширения SelectList, ни метод расширения DropDownList не поддерживают использование OptGroup при выборе.Похоже, вам нужно будет написать свой собственный метод расширения и расширить SelectListItem, чтобы он содержал группировку, или сгенерировать выбор вручную в разметке.
Другие советы
Мое расширение немного сложнее, но оно имеет все перегрузки, как и оригинальный 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;
}
}
Это было добавлено в ASP.Net MVC версии 5.2 и теперь встроено.
А Свойство Group в SelectListItem позволяет указать группу для каждого элемента:
Новый Конструкторы SelectList также позволяет вам указать имя поля, которое содержит заголовок группы в предоставленном списке элементов.
Методы HtmlHelper DropDownList и DropDownListFor теперь генерируют элементы optgroup на основе групп, включенных в список элементов.
Легкий!
Я просто пишу расширения для этого, посмотрите:
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; }
}
}
Отсутствуют аннотации к данным для проверки клиента?
В ответ на вопрос Чрно Лава выше, добавление к решению Сержа Заба - исправление 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);
}
Ответ Сержа Заба был именно тем, что я искал.Будучи заядлым программистом 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
Я пробовал решение @Serge Zab, которое работает хорошо, но у меня возникли проблемы с ненавязчивой проверкой, после некоторой проверки я обнаружил проблему.
Кажется, в элементе выбора отсутствуют некоторые обязательные атрибуты, если вы хотите, чтобы проверка Jquery запускалась сразу после создания TagBuilder.
TagBuilder tagBuilder = new TagBuilder("select");
Добавьте эти атрибуты
tagBuilder.MergeAttribute("data-val", "true",true);
tagBuilder.MergeAttribute("data-val-required", "your validation message", true)
и ненавязчивая проверка должна сработать.
У Сержа Заба отвечать, атрибуты данных, например data_valuename
, не делайте полей в правильной форме data-valuename
.
я заменил код tagBuilder.MergeAttributes(htmlAttributes);
в SelectInternal
метод для этого
foreach (var htmlAttribute in htmlAttributes)
{
tagBuilder.MergeAttribute(
htmlAttribute.Key.Replace('_', '-'),
(string)htmlAttribute.Value
);
}
Просто примечание об использовании расширения Сержа для создания более одного списка выбора в одной форме.У меня были проблемы с получением второго списка выбора для применения групп, и когда я изучил сгенерированный HTML-код, я понял, что им обоим был присвоен один и тот же идентификатор.Чтобы это исправить, войдите в функцию SelectInternal в расширении serge и закомментируйте/удалите следующие две строки:
tagBuilder.MergeAttribute("name", name, true /* replaceExisting */);tagBuilder.GenerateId(имя);
В качестве альтернативы вы можете просто передать каждому уникальный идентификатор (хотя DropDownGroupListFor не принимает параметр «имя строки», поэтому вам придется добавить перегрузку, которая это делает)
Мне нужно было решение для обработки множественного выбора с помощью optgroup, и я использовал решение Serge Zab.У меня всего два комментария по этому поводу (слишком долго для комментария).
Несмотря на его заявления, его решение не поддерживает все существующие перегрузки DropDownListFor, поскольку оно не поддерживает MultiSelectList или SelectList, часто используемые в моделях.Но добавить их несложно.
Его решение не помогло мне при множественном выборе для инициализации выбранных/не выбранных элементов из модели:первоначальные значения не были затронуты.Я только что изменил следующий метод:
Private Static MVCHTMLSTRING DROUTDOWNDLISTHELPER (...) {return SelectInternal (htmlHelper, OptionLabel, выражение, SelectList, false / * 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);
}
И это сработало, как и ожидалось.Конечно, атрибут Multiple должен быть определен:@Html.DropDownGroupListFor(m => m.Selected, Model.Values, new { Multiple = "multiple" })
Спасибо Сергею за ответ.