| File: Rendering\MultiSelectList.cs | Web Access |
| Project: src\aspnetcore\src\Mvc\Mvc.ViewFeatures\src\Microsoft.AspNetCore.Mvc.ViewFeatures.csproj (Microsoft.AspNetCore.Mvc.ViewFeatures) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Mvc.ViewFeatures; namespace Microsoft.AspNetCore.Mvc.Rendering; /// <summary> /// Represents a list that lets users select multiple items. /// This class is typically rendered as an HTML <c><select multiple="multiple"></c> element with the specified collection /// of <see cref="SelectListItem"/> objects. /// </summary> public class MultiSelectList : IEnumerable<SelectListItem> { private readonly IList<SelectListGroup> _groups; private IList<SelectListItem> _selectListItems; /// <summary> /// Initialize a new instance of <see cref="MultiSelectList"/>. /// </summary> /// <param name="items">The items.</param> public MultiSelectList(IEnumerable items) : this(items, selectedValues: null) { ArgumentNullException.ThrowIfNull(items); } /// <summary> /// Initialize a new instance of <see cref="MultiSelectList"/>. /// </summary> /// <param name="items">The items.</param> /// <param name="selectedValues">The selected values.</param> public MultiSelectList(IEnumerable items, IEnumerable selectedValues) : this(items, dataValueField: null, dataTextField: null, selectedValues: selectedValues) { ArgumentNullException.ThrowIfNull(items); } /// <summary> /// Initialize a new instance of <see cref="MultiSelectList"/>. /// </summary> /// <param name="items">The items.</param> /// <param name="dataValueField">The data value field.</param> /// <param name="dataTextField">The data text field.</param> public MultiSelectList(IEnumerable items, string dataValueField, string dataTextField) : this(items, dataValueField, dataTextField, selectedValues: null) { ArgumentNullException.ThrowIfNull(items); } /// <summary> /// Initialize a new instance of <see cref="MultiSelectList"/>. /// </summary> /// <param name="items">The items.</param> /// <param name="dataValueField">The data value field.</param> /// <param name="dataTextField">The data text field.</param> /// <param name="selectedValues">The selected values.</param> public MultiSelectList( IEnumerable items, string dataValueField, string dataTextField, IEnumerable selectedValues) : this(items, dataValueField, dataTextField, selectedValues, dataGroupField: null) { ArgumentNullException.ThrowIfNull(items); } /// <summary> /// Initializes a new instance of the MultiSelectList class by using the items to include in the list, /// the data value field, the data text field, the selected values, and the data group field. /// </summary> /// <param name="items">The items used to build each <see cref="SelectListItem"/> of the list.</param> /// <param name="dataValueField">The data value field. Used to match the Value property of the corresponding /// <see cref="SelectListItem"/>.</param> /// <param name="dataTextField">The data text field. Used to match the Text property of the corresponding /// <see cref="SelectListItem"/>.</param> /// <param name="selectedValues">The selected values field. Used to match the Selected property of the /// corresponding <see cref="SelectListItem"/>.</param> /// <param name="dataGroupField">The data group field. Used to match the Group property of the corresponding /// <see cref="SelectListItem"/>.</param> public MultiSelectList( IEnumerable items, string dataValueField, string dataTextField, IEnumerable selectedValues, string dataGroupField) { ArgumentNullException.ThrowIfNull(items); Items = items; DataValueField = dataValueField; DataTextField = dataTextField; SelectedValues = selectedValues; DataGroupField = dataGroupField; if (DataGroupField != null) { _groups = new List<SelectListGroup>(); } } /// <summary> /// Gets the data group field. /// </summary> public string DataGroupField { get; } /// <summary> /// Gets the data text field. /// </summary> public string DataTextField { get; } /// <summary> /// Gets the data value field. /// </summary> public string DataValueField { get; } /// <summary> /// Gets the items. /// </summary> public IEnumerable Items { get; } /// <summary> /// Gets the selected values. /// </summary> public IEnumerable SelectedValues { get; } /// <inheritdoc /> public virtual IEnumerator<SelectListItem> GetEnumerator() { if (_selectListItems == null) { _selectListItems = GetListItems(); } return _selectListItems.GetEnumerator(); } private IList<SelectListItem> GetListItems() { return (!string.IsNullOrEmpty(DataValueField)) ? GetListItemsWithValueField() : GetListItemsWithoutValueField(); } private IList<SelectListItem> GetListItemsWithValueField() { var selectedValues = new HashSet<string>(StringComparer.OrdinalIgnoreCase); if (SelectedValues != null) { foreach (var value in SelectedValues) { var stringValue = Convert.ToString(value, CultureInfo.CurrentCulture); selectedValues.Add(stringValue); } } var listItems = new List<SelectListItem>(); foreach (var item in Items) { var value = Eval(item, DataValueField); var newListItem = new SelectListItem { Group = GetGroup(item), Value = value, Text = Eval(item, DataTextField), Selected = selectedValues.Contains(value), }; listItems.Add(newListItem); } return listItems; } private IList<SelectListItem> GetListItemsWithoutValueField() { var selectedValues = new HashSet<object>(); if (SelectedValues != null) { selectedValues.UnionWith(SelectedValues.Cast<object>()); } var listItems = new List<SelectListItem>(); foreach (var item in Items) { var newListItem = new SelectListItem { Group = GetGroup(item), Text = Eval(item, DataTextField), Selected = selectedValues.Contains(item), }; listItems.Add(newListItem); } return listItems; } private static string Eval(object container, string expression) { var value = container; if (!string.IsNullOrEmpty(expression)) { var viewDataInfo = ViewDataEvaluator.Eval(container, expression); value = viewDataInfo.Value; } return Convert.ToString(value, CultureInfo.CurrentCulture); } private SelectListGroup GetGroup(object container) { if (_groups == null) { return null; } var groupName = Eval(container, DataGroupField); if (string.IsNullOrEmpty(groupName)) { return null; } // We use StringComparison.CurrentCulture because the group name is used to display as the value of // optgroup HTML tag's label attribute. SelectListGroup group = null; for (var index = 0; index < _groups.Count; index++) { if (string.Equals(_groups[index].Name, groupName, StringComparison.CurrentCulture)) { group = _groups[index]; break; } } if (group == null) { group = new SelectListGroup() { Name = groupName }; _groups.Add(group); } return group; } #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion }