namespace System.Web.Mvc.Html { using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Web; using System.Web.Mvc.Resources; public static class SelectExtensions { // DropDownList public static MvcHtmlString DropDownList(this HtmlHelper htmlHelper, string name) { return DropDownList(htmlHelper, name, null /* selectList */, null /* optionLabel */, null /* htmlAttributes */); } public static MvcHtmlString DropDownList(this HtmlHelper htmlHelper, string name, string optionLabel) { return DropDownList(htmlHelper, name, null /* selectList */, optionLabel, null /* htmlAttributes */); } public static MvcHtmlString DropDownList(this HtmlHelper htmlHelper, string name, IEnumerable selectList) { return DropDownList(htmlHelper, name, selectList, null /* optionLabel */, null /* htmlAttributes */); } public static MvcHtmlString DropDownList(this HtmlHelper htmlHelper, string name, IEnumerable selectList, object htmlAttributes) { return DropDownList(htmlHelper, name, selectList, null /* optionLabel */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); } public static MvcHtmlString DropDownList(this HtmlHelper htmlHelper, string name, IEnumerable selectList, IDictionary htmlAttributes) { return DropDownList(htmlHelper, name, selectList, null /* optionLabel */, htmlAttributes); } public static MvcHtmlString DropDownList(this HtmlHelper htmlHelper, string name, IEnumerable selectList, string optionLabel) { return DropDownList(htmlHelper, name, selectList, optionLabel, null /* htmlAttributes */); } public static MvcHtmlString DropDownList(this HtmlHelper htmlHelper, string name, IEnumerable selectList, string optionLabel, object htmlAttributes) { return DropDownList(htmlHelper, name, selectList, optionLabel, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); } public static MvcHtmlString DropDownList(this HtmlHelper htmlHelper, string name, IEnumerable selectList, string optionLabel, IDictionary htmlAttributes) { return DropDownListHelper(htmlHelper, name, selectList, optionLabel, htmlAttributes); } [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString DropDownListFor(this HtmlHelper htmlHelper, Expression> expression, IEnumerable selectList) { return DropDownListFor(htmlHelper, expression, selectList, null /* optionLabel */, null /* htmlAttributes */); } [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString DropDownListFor(this HtmlHelper htmlHelper, Expression> expression, IEnumerable selectList, object htmlAttributes) { return DropDownListFor(htmlHelper, expression, selectList, null /* optionLabel */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); } [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString DropDownListFor(this HtmlHelper htmlHelper, Expression> expression, IEnumerable selectList, IDictionary htmlAttributes) { return DropDownListFor(htmlHelper, expression, selectList, null /* optionLabel */, htmlAttributes); } [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString DropDownListFor(this HtmlHelper htmlHelper, Expression> expression, IEnumerable selectList, string optionLabel) { return DropDownListFor(htmlHelper, expression, selectList, optionLabel, null /* htmlAttributes */); } [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString DropDownListFor(this HtmlHelper htmlHelper, Expression> expression, IEnumerable selectList, string optionLabel, object htmlAttributes) { return DropDownListFor(htmlHelper, expression, selectList, optionLabel, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); } [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Users cannot use anonymous methods with the LambdaExpression type")] [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString DropDownListFor(this HtmlHelper htmlHelper, Expression> expression, IEnumerable selectList, string optionLabel, IDictionary 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 selectList, string optionLabel, IDictionary htmlAttributes) { return SelectInternal(htmlHelper, optionLabel, expression, selectList, false /* allowMultiple */, htmlAttributes); } // ListBox public static MvcHtmlString ListBox(this HtmlHelper htmlHelper, string name) { return ListBox(htmlHelper, name, null /* selectList */, null /* htmlAttributes */); } public static MvcHtmlString ListBox(this HtmlHelper htmlHelper, string name, IEnumerable selectList) { return ListBox(htmlHelper, name, selectList, (IDictionary)null); } public static MvcHtmlString ListBox(this HtmlHelper htmlHelper, string name, IEnumerable selectList, object htmlAttributes) { return ListBox(htmlHelper, name, selectList, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); } public static MvcHtmlString ListBox(this HtmlHelper htmlHelper, string name, IEnumerable selectList, IDictionary htmlAttributes) { return ListBoxHelper(htmlHelper, name, selectList, htmlAttributes); } [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString ListBoxFor(this HtmlHelper htmlHelper, Expression> expression, IEnumerable selectList) { return ListBoxFor(htmlHelper, expression, selectList, null /* htmlAttributes */); } [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString ListBoxFor(this HtmlHelper htmlHelper, Expression> expression, IEnumerable selectList, object htmlAttributes) { return ListBoxFor(htmlHelper, expression, selectList, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); } [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Users cannot use anonymous methods with the LambdaExpression type")] [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")] public static MvcHtmlString ListBoxFor(this HtmlHelper htmlHelper, Expression> expression, IEnumerable selectList, IDictionary htmlAttributes) { if (expression == null) { throw new ArgumentNullException("expression"); } return ListBoxHelper(htmlHelper, ExpressionHelper.GetExpressionText(expression), selectList, htmlAttributes); } private static MvcHtmlString ListBoxHelper(HtmlHelper htmlHelper, string name, IEnumerable selectList, IDictionary htmlAttributes) { return SelectInternal(htmlHelper, null /* optionLabel */, name, selectList, true /* allowMultiple */, htmlAttributes); } // Helper methods private static IEnumerable 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, MvcResources.HtmlHelper_MissingSelectData, name, "IEnumerable")); } IEnumerable selectList = o as IEnumerable; if (selectList == null) { throw new InvalidOperationException( String.Format( CultureInfo.CurrentCulture, MvcResources.HtmlHelper_WrongSelectDataType, name, o.GetType().FullName, "IEnumerable")); } return selectList; } internal static string ListItemToOption(SelectListItem 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"; } return builder.ToString(TagRenderMode.Normal); } private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, string optionLabel, string name, IEnumerable selectList, bool allowMultiple, IDictionary htmlAttributes) { string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name); if (String.IsNullOrEmpty(fullName)) { throw new ArgumentException(MvcResources.Common_NullOrEmpty, "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(fullName); usedViewData = true; } 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 (!usedViewData) { if (defaultValue == null) { defaultValue = htmlHelper.ViewData.Eval(fullName); } } if (defaultValue != null) { IEnumerable defaultValues = (allowMultiple) ? defaultValue as IEnumerable : new[] { defaultValue }; IEnumerable values = from object value in defaultValues select Convert.ToString(value, CultureInfo.CurrentCulture); HashSet selectedValues = new HashSet(values, StringComparer.OrdinalIgnoreCase); List newSelectList = new List(); foreach (SelectListItem 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