Si no creemos que este sea un error que el equipo debería corregir, al menos MSDN debería mejorar el documento. La confusión proviene realmente del mal documento de esto. En MSDN , explica el nombre de los parámetros como,
Type: System.String
The name of the form field to return.
Esto solo significa que el html final que genera usará ese parámetro como el nombre de la entrada seleccionada. Pero, en realidad, significa más que eso.
Supongo que el diseñador asume que el usuario usará un modelo de vista para mostrar la lista desplegable, y también usará la publicación de regreso al mismo modelo de vista. Pero en muchos casos, realmente no seguimos esa suposición.
Utilice el ejemplo anterior,
public class Person {
public int Id { get; set; }
public string Name { get; set; }
}
Si seguimos la suposición, deberíamos definir un modelo de vista para esta vista relacionada con la lista desplegable
public class PersonsSelectViewModel{
public string SelectedPersonId,
public List<SelectListItem> Persons;
}
Porque cuando se publica, solo se publicará el valor seleccionado, por lo que se asume que se debe publicar en la propiedad del modelo SelectedPersonId, lo que significa que el primer nombre de parámetro de Html.DropDownList debe ser 'SelectedPersonId'. Por lo tanto, el diseñador piensa que cuando se muestra la vista del modelo en la vista, la propiedad del modelo SelectedPersonId debería contener el valor predeterminado de esa lista desplegable. Incluso aunque su Lista <SelectListItem> Personas ya haya configurado el indicador Seleccionado para indicar cuál está seleccionado / predeterminado, tml.DropDownList lo ignorará y reconstruirá su propio IEnumerable <SelectListItem> y establecerá el elemento predeterminado / seleccionado según el nombre.
Aquí está el código de 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);
}
Entonces, el código en realidad fue más allá, no solo intenta buscar el nombre en el modelo, sino también en los datos de vista, tan pronto como encuentre uno, reconstruirá la lista de selección e ignorará su Seleccionado original.
El problema es que, en muchos casos, realmente no lo usamos de esa manera. solo queremos incluir una lista de selección con uno o varios elementos seleccionados como verdadero.
Por supuesto, la solución es simple, use un nombre que no esté en el modelo ni en los datos de vista. Cuando no puede encontrar una coincidencia, utilizará la lista de selección original y la selección original tendrá efecto.
Pero sigo pensando que MVC debería mejorarlo agregando una condición más
if ((defaultValue != null) && (!selectList.Any(i=>i.Selected)))
{
selectList = GetSelectListWithDefaultValue(selectList, defaultValue, allowMultiple);
}
Porque, si la selectList original ya ha tenido una seleccionada, ¿por qué ignoraría eso?
Solo mis pensamientos.