在Html.DropDownList </option>中的<option>下添加html类标记

时间:2011-09-24 02:37:31

标签: html asp.net-mvc html-select

我一直在寻找有关如何在html.dropdownlist上添加HTML类标记的答案。这是代码

<%: Html.DropDownList("PackageId", new SelectList(ViewData["Packages"] as IEnumerable, "PackageId", "Name", Model.PackageId))%>

我想在select元素下添加选项类,以便我可以使用这个链式选择:

<select id="category">
  <option value="1">One</option>
  <option value="2">Two</option>
</select>
<select id="package">
  <option value="1" class="1">One - package1</option>
  <option value="2" class="1">One - package2</option>
  <option value="3" class="2">Two - package1</option>
  <option value="4" class="2">Two - package2</option>
</select>

$("#series").chained("#mark");

7 个答案:

答案 0 :(得分:51)

我已经为DropDownlistFor扩展方法做了这个,而不是你使用的DropDownList,但是你可以自己解决这个问题。这些东西主要是来自MVC源的复制/粘贴。您可以找到来源here

public class ExtendedSelectListItem : SelectListItem
{
    public object htmlAttributes { get; set; }
}

public static partial class HtmlHelperExtensions
{
    public static MvcHtmlString ExtendedDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<ExtendedSelectListItem> selectList, string optionLabel, object htmlAttributes)
    {
        return SelectInternal(htmlHelper, optionLabel, ExpressionHelper.GetExpressionText(expression), selectList, false /* allowMultiple */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

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

        if (selectList == null)
            throw new ArgumentException("No selectlist");

        object defaultValue = (allowMultiple) ? GetModelStateValue(htmlHelper, fullName, typeof(string[])) : GetModelStateValue(htmlHelper, fullName, 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 (defaultValue == null)
            defaultValue = htmlHelper.ViewData.Eval(fullName);

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

            foreach (ExtendedSelectListItem 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
        StringBuilder listItemBuilder = new StringBuilder();

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

        foreach (ExtendedSelectListItem item in selectList)
        {
            listItemBuilder.Append(ListItemToOption(item));
        }

        TagBuilder tagBuilder = new TagBuilder("select")
        {
            InnerHtml = listItemBuilder.ToString()
        };
        tagBuilder.MergeAttributes(htmlAttributes);
        tagBuilder.MergeAttribute("name", fullName, true /* replaceExisting */);
        tagBuilder.GenerateId(fullName);
        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(fullName, out modelState))
        {
            if (modelState.Errors.Count > 0)
            {
                tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
            }
        }

        tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(name));

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

    internal static string ListItemToOption(ExtendedSelectListItem item)
    {
        TagBuilder 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";
        }
        builder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(item.htmlAttributes));
        return builder.ToString(TagRenderMode.Normal);
    }
}

答案 1 :(得分:13)

这是@ john-landheer解决方案的一个小改进版本。

事情有所改善:

  • GetModelStateValue()修复
  • 的问题
  • DropDownList()已添加扩展方法
  • 不显眼的验证属性将像它们应该

    一样呈现
    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;
    
    namespace App.Infrastructure.Helpers
    {
        public class ExtendedSelectListItem : SelectListItem
        {
            public object HtmlAttributes { get; set; }
        }
    
        public static class ExtendedSelectExtensions
        {
            internal static object GetModelStateValue(this HtmlHelper htmlHelper, string key, Type destinationType)
            {
                System.Web.Mvc.ModelState modelState;
                if (htmlHelper.ViewData.ModelState.TryGetValue(key, out modelState))
                {
                    if (modelState.Value != null)
                    {
                        return modelState.Value.ConvertTo(destinationType, null /* culture */);
                    }
                }
                return null;
            }
    
            public static MvcHtmlString ExtendedDropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<ExtendedSelectListItem> selectList)
            {
                return ExtendedDropDownList(htmlHelper, name, selectList, (string)null, (IDictionary<string, object>)null);
            }
    
            public static MvcHtmlString ExtendedDropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<ExtendedSelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes)
            {
                return ExtendedDropDownListHelper(htmlHelper, null, name, selectList, optionLabel, htmlAttributes);
            }
    
            public static MvcHtmlString ExtendedDropDownListHelper(this HtmlHelper htmlHelper, ModelMetadata metadata, string expression, IEnumerable<ExtendedSelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes)
            {
                return SelectInternal(htmlHelper, metadata, optionLabel, expression, selectList, false, htmlAttributes);
            }
    
            public static MvcHtmlString ExtendedDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
                Expression<Func<TModel, TProperty>> expression, IEnumerable<ExtendedSelectListItem> selectList,
                string optionLabel, object htmlAttributes)
            {
                if (expression == null)
                    throw new ArgumentNullException("expression");
                ModelMetadata metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData);
                return SelectInternal(htmlHelper, metadata, optionLabel, ExpressionHelper.GetExpressionText(expression), selectList,
                    false /* allowMultiple */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
            }
    
            private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata, string optionLabel, string name,
                IEnumerable<ExtendedSelectListItem> selectList, bool allowMultiple,
                IDictionary<string, object> htmlAttributes)
            {
                string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
                if (String.IsNullOrEmpty(fullName))
                    throw new ArgumentException("No name");
    
                if (selectList == null)
                    throw new ArgumentException("No selectlist");
    
                object defaultValue = (allowMultiple)
                    ? htmlHelper.GetModelStateValue(fullName, typeof(string[]))
                    : htmlHelper.GetModelStateValue(fullName, 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 (defaultValue == null)
                    defaultValue = htmlHelper.ViewData.Eval(fullName);
    
                if (defaultValue != null)
                {
                    IEnumerable defaultValues = (allowMultiple) ? defaultValue as IEnumerable : new[] { defaultValue };
                    IEnumerable<string> values = from object value in defaultValues
                                                 select Convert.ToString(value, CultureInfo.CurrentCulture);
                    HashSet<string> selectedValues = new HashSet<string>(values, StringComparer.OrdinalIgnoreCase);
                    List<ExtendedSelectListItem> newSelectList = new List<ExtendedSelectListItem>();
    
                    foreach (ExtendedSelectListItem 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
                StringBuilder listItemBuilder = new StringBuilder();
    
                // Make optionLabel the first item that gets rendered.
                if (optionLabel != null)
                    listItemBuilder.Append(
                        ListItemToOption(new ExtendedSelectListItem()
                        {
                            Text = optionLabel,
                            Value = String.Empty,
                            Selected = false
                        }));
    
                foreach (ExtendedSelectListItem item in selectList)
                {
                    listItemBuilder.Append(ListItemToOption(item));
                }
    
                TagBuilder tagBuilder = new TagBuilder("select")
                {
                    InnerHtml = listItemBuilder.ToString()
                };
                tagBuilder.MergeAttributes(htmlAttributes);
                tagBuilder.MergeAttribute("name", fullName, true /* replaceExisting */);
                tagBuilder.GenerateId(fullName);
                if (allowMultiple)
                    tagBuilder.MergeAttribute("multiple", "multiple");
    
                // If there are any errors for a named field, we add the css attribute.
                System.Web.Mvc.ModelState modelState;
                if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState))
                {
                    if (modelState.Errors.Count > 0)
                    {
                        tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
                    }
                }
    
                tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(fullName, metadata));
    
                return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal));
            }
    
            internal static string ListItemToOption(ExtendedSelectListItem item)
            {
                TagBuilder 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";
                }
                builder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(item.HtmlAttributes));
                return builder.ToString(TagRenderMode.Normal);
            }
    
        }
    }
    

答案 2 :(得分:5)

使用ASP.NET MVC中内置的DropDownList帮助程序是不可能的。因此,如果您需要这样做,您将不得不编写自己的帮助程序。您可以查看ASP.NET MVC的源代码,它使用TagBuilder生成选项,您可以在自定义实现中附加任何属性。另一个不太优雅的解决方案是手动遍历视图中的数据集并生成单独的选项元素。

答案 3 :(得分:2)

我想到的第一件事是JQuery。您可以使用以下代码轻松完成此操作:

$("#bla").find("option").addClass("poo");

答案 4 :(得分:1)

一个简单的解决方案: 当您添加

@Html.DropDownList("someID", new SelectList(Model.selectItems),"--Select--",new { @class= "select-ddl" })

在您的CSS中再添加一类

.select-ddl option {}

该类将应用于HTML中的所有选项标签。

答案 5 :(得分:0)

我写了一个简单修改html的包装器:

    public static MvcHtmlString DisableFirstItem(MvcHtmlString htmlString)
    {
        return new MvcHtmlString(
            htmlString.ToString()
            .Replace("<option value=\"Unknown\">", 
                     "<option disabled value=\"Unknown\">")
        );
    }

然后我用这个辅助函数包装了我的DropDownListFor:

        @Html.Raw(MyHtmlHelpers.DisableFirstItem(

          Html.DropDownListFor(m => m.Instrument,
            new SelectList(ReflectionHelpers.GenerateEnumDictionary<OrderInstrument>(true), "Key", "Value", Model.Instrument),
            new { @class = "form-control" })

        ))

如果你愿意,显然你可以让助手功能更复杂。

答案 6 :(得分:0)

我修改了@Alexander Puchkov答案,以便自动创建一个ExtendedSelectList,其中包含ExtendedSelectListItems的集合,该集合是从传递给它的Items的属性自动生成的,而不必手动为每个SelectListItem指定属性。它将属性创建为“ data- *”。您可以使用函数parms或通过将它们列出在excludeProperties中来排除某些属性。

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

namespace App.Infrastructure.Helpers.Extensions
{
    public class ExtendedSelectList : SelectList
    {
        static readonly string[] excludedProperties = new string[] { "DateInsert", "DateUpdate" }; // Write here properties you want to exclude for every ExtendedSelectList
        public ICollection<ExtendedSelectListItem> ExtendedSelectListItems { get; set; }
        public ExtendedSelectList(IEnumerable items, string dataValueField, string dataTextField, object selectedValue, params string[] exclude) : base(items, dataValueField, dataTextField, selectedValue)
        {
            ExtendedSelectListItems = new List<ExtendedSelectListItem>();
            exclude = exclude.Concat(new string[] { dataValueField, dataTextField }).ToArray();
            exclude = exclude.Concat(excludedProperties).ToArray();
            foreach (var selectListItem in this.AsEnumerable())
            {
                var extendedItem = new ExtendedSelectListItem() { Value = selectListItem.Value, Text = selectListItem.Text, Selected = selectListItem.Selected, Disabled = selectListItem.Disabled, Group = selectListItem.Group };
                var htmlAttributes = new Dictionary<string, object>();
                var item = items.Cast<object>().FirstOrDefault(x =>
                {
                    string valueItem = DataBinder.Eval(x, DataValueField).ToString();
                    string valueSelectListItem = DataBinder.Eval(selectListItem, "Value").ToString();
                    return valueItem == valueSelectListItem;
                });
                foreach (PropertyInfo property in item.GetType().GetProperties())
                {
                    if (!property.CanRead || (property.GetIndexParameters().Length > 0) || (exclude != null && exclude.Contains(property.Name)))
                        continue;

                    htmlAttributes.Add("data-" + property.Name.ToLower(), property.GetValue(item));
                }
                extendedItem.HtmlAttributesDict = htmlAttributes;
                ExtendedSelectListItems.Add(extendedItem);
            }
        }
    }
    public class ExtendedSelectListItem : SelectListItem
    {
        public object HtmlAttributes { get; set; }
        public Dictionary<string, object> HtmlAttributesDict { get; set; }
    }

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

        public static MvcHtmlString ExtendedDropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<ExtendedSelectListItem> selectList)
        {
            return ExtendedDropDownList(htmlHelper, name, selectList, (string)null, (IDictionary<string, object>)null);
        }

        public static MvcHtmlString ExtendedDropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<ExtendedSelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes)
        {
            return ExtendedDropDownListHelper(htmlHelper, null, name, selectList, optionLabel, htmlAttributes);
        }

        public static MvcHtmlString ExtendedDropDownListHelper(this HtmlHelper htmlHelper, ModelMetadata metadata, string expression, IEnumerable<ExtendedSelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes)
        {
            return SelectInternal(htmlHelper, metadata, optionLabel, expression, selectList, false, htmlAttributes);
        }

        public static MvcHtmlString ExtendedDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TProperty>> expression, IEnumerable<ExtendedSelectListItem> selectList,
            string optionLabel, object htmlAttributes)
        {
            if (expression == null)
                throw new ArgumentNullException("expression");
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData);
            return SelectInternal(htmlHelper, metadata, optionLabel, ExpressionHelper.GetExpressionText(expression), selectList,
                false /* allowMultiple */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }

        private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata, string optionLabel, string name,
            IEnumerable<ExtendedSelectListItem> selectList, bool allowMultiple,
            IDictionary<string, object> htmlAttributes)
        {
            string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
            if (String.IsNullOrEmpty(fullName))
                throw new ArgumentException("No name");

            if (selectList == null)
                throw new ArgumentException("No selectlist");

            object defaultValue = (allowMultiple)
                ? htmlHelper.GetModelStateValue(fullName, typeof(string[]))
                : htmlHelper.GetModelStateValue(fullName, 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 (defaultValue == null)
                defaultValue = htmlHelper.ViewData.Eval(fullName);

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

                foreach (ExtendedSelectListItem 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
            StringBuilder listItemBuilder = new StringBuilder();

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

            foreach (ExtendedSelectListItem item in selectList)
            {
                listItemBuilder.Append(ListItemToOption(item));
            }

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

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

            tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(fullName, metadata));

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

        internal static string ListItemToOption(ExtendedSelectListItem item)
        {
            TagBuilder 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";
            }
            var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(item.HtmlAttributes);
            builder.MergeAttributes(attributes);
            if (item.HtmlAttributesDict != null)
            {
                foreach (var attribute in item.HtmlAttributesDict)
                {
                    var key = attribute.Key.ToLower(); // We call ToLower to keep the same naming convention used by MVC's HtmlHelper.AnonymousObjectToHtmlAttributes
                    var value = attribute.Value?.ToString() ?? "";
                    builder.Attributes[key] = value;
                }
            }
            return builder.ToString(TagRenderMode.Normal);
        }

    }
}

要在Razor中使用它,请执行以下操作:

@{
    var availableLocations = new ExtendedSelectList(Model.AvailableLocations, "Id", "Value", Model.LocationId);
}
@Html.ExtendedDropDownListFor(m => Model.LocationId, availableLocations.ExtendedSelectListItems, null, new { id = "ddLocation" })

请注意“ availableLocations.ExtendedSelectListItems”,因为您不能直接使用Enumerable项目,因为它们是简单的SelectListItem