Если мы не думаем, что это ошибка, которую команда должна исправить, в любом случае MSDN должен улучшить документ. Сложность действительно возникает из-за плохого документа. В MSDN это объясняет имя параметров как,
Type: System.String
The name of the form field to return.
Это просто означает, что конечный HTML-код, который он сгенерирует, будет использовать этот параметр в качестве имени ввода выбора. Но на самом деле это означает нечто большее.
Я предполагаю, что дизайнер предполагает, что пользователь будет использовать модель представления для отображения раскрывающегося списка, а также будет использовать отправку обратно в ту же модель представления. Но во многих случаях мы не следуем этому предположению.
Используйте приведенный выше пример,
public class Person {
public int Id { get; set; }
public string Name { get; set; }
}
Если мы последуем предположению, мы должны определить модель представления для этого представления, связанного с выпадающим списком.
public class PersonsSelectViewModel{
public string SelectedPersonId,
public List<SelectListItem> Persons;
}
Потому что , когда пост обратно, только выбранное значение будет размещать назад, поэтому предположим , что следует размещать обратно в собственность SelectedPersonId модели, что означает первый параметр Html.DropDownList по имени должно быть «SelectedPersonId». Таким образом, дизайнер считает, что при отображении вида модели в представлении свойство модели SelectedPersonId должно содержать значение по умолчанию для этого раскрывающегося списка. Даже если подумать, что ваши List <SelectListItem> Persons уже установили флаг Selected, чтобы указать, какой из них выбран / по умолчанию, tml.DropDownList фактически проигнорирует это и перестроит свой собственный IEnumerable <SelectListItem> и установит элемент по умолчанию / выбранный на основе имени.
Вот код из asp.net mvc
private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata,
string optionLabel, string name, IEnumerable<SelectListItem> selectList, bool allowMultiple,
IDictionary<string, object> htmlAttributes)
{
...
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(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 && !String.IsNullOrEmpty(name))
{
if (!usedViewData)
{
defaultValue = htmlHelper.ViewData.Eval(name);
}
else if (metadata != null)
{
defaultValue = metadata.Model;
}
}
if (defaultValue != null)
{
selectList = GetSelectListWithDefaultValue(selectList, defaultValue, allowMultiple);
}
...
return tagBuilder.ToMvcHtmlString(TagRenderMode.Normal);
}
Итак, код на самом деле пошел дальше, он не только пытается найти имя в модели, но и в данных представления, как только он его найдет, он перестроит selectList и проигнорирует исходное Selected.
Проблема в том, что во многих случаях мы так не используем. мы просто хотим добавить selectList с одним / несколькими элементами.
Конечно, решение простое - используйте имя, которого нет ни в модели, ни в данных представления. Если он не может найти совпадение, он будет использовать исходный список selectList, и исходный Selected вступит в силу.
Но я все еще думаю, что mvc должен улучшить его, добавив еще одно условие
if ((defaultValue != null) && (!selectList.Any(i=>i.Selected)))
{
selectList = GetSelectListWithDefaultValue(selectList, defaultValue, allowMultiple);
}
Потому что, если в исходном списке selectList уже был выбран один элемент, почему бы вам его игнорировать?
Только мои мысли.