Si no creemos que esto es un error que el equipo debe fijar, en el arriendo de MSDN debería mejorar el documento. La confusión realmente proviene del pobre documento de esto. En MSDN, se explican los parámetros nombre como,
Type: System.String
The name of the form field to return.
Esto sólo significa el final de HTML que genera va a utilizar ese parámetro como el nombre de la selección de entrada. Pero, en realidad significa más que eso.
Supongo que el diseñador asume que el usuario utilizará un modelo de vista para mostrar la lista desplegable, también utilizará la publicación de nuevo en el modelo de vista misma. 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 hipótesis, debemos definir un modelo de vista para esta vista relacionados con lista desplegable
public class PersonsSelectViewModel{
public string SelectedPersonId,
public List<SelectListItem> Persons;
}
Porque cuando segundo palo, sólo el valor seleccionado publicar de nuevo, por lo que supone que debe publicar de nuevo en la propiedad del modelo SelectedPersonId, lo que significa que el primer parámetro de Html.DropDownList nombre debe ser 'SelectedPersonId'. Por lo tanto, el diseñador piensa que cuando se muestra la vista del modelo en la vista, la propiedad SelectedPersonId del modelo debe contener el valor predeterminado de esa lista desplegable. Aunque su lista < SelectListItem> Personas ya estableció el indicador seleccionado para indicar cuál se selecciona/predeterminado, el tml.DropDownList ignorará eso 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);
}
Por lo tanto, el código en realidad fueron más allá, no sólo se trata de buscar el nombre en el modelo, sino también en el viewdata, tan pronto como sea encuentra uno, reconstruirá la lista de selección e ignorará su selección original.
El problema es que, en muchos casos, realmente no lo utilizamos de esa manera. solo queremos agregar una lista de selección con uno/varios ítems seleccionados seleccionados como verdaderos.
Por supuesto, la solución es simple, use un nombre que no esté en el modelo ni en la vista. Cuando no puede encontrar una coincidencia, utilizará la lista de selección original y la selección original tendrá efecto.
pero sigo pensando MVC debe mejorarlo por añadir una condición más
if ((defaultValue != null) && (!selectList.Any(i=>i.Selected)))
{
selectList = GetSelectListWithDefaultValue(selectList, defaultValue, allowMultiple);
}
Porque, si el original ha selectlist ya había seleccionado, ¿por qué ignorar eso?
Sólo mis pensamientos.
¿Está seguro de que el valor está en la lista? –
sí, está en la lista – blu
¿Qué es selectedUserId? – fuzz