asp.net-mvc - net - html dropdownlistfor selected value not working
ASP.NET MVC Html.DropDownList SelectedValue (8)
He intentado esto RC1 y luego actualicé a RC2 que no resolvió el problema.
// in my controller
ViewData["UserId"] = new SelectList(
users,
"UserId",
"DisplayName",
selectedUserId.Value); // this has a value
resultado: la propiedad SelectedValue se establece en el objeto
// in my view
<%=Html.DropDownList("UserId", (SelectList)ViewData["UserId"])%>
resultado: todas las opciones esperadas se representan al cliente, pero el atributo seleccionado no está establecido. El elemento en SelectedValue existe dentro de la lista, pero el primer elemento de la lista siempre está predeterminado en selected.
¿Cómo debería estar haciendo esto?
Actualización Gracias a la respuesta de John Feminella, descubrí cuál es el problema. "UserId" es una propiedad del Modelo en el que mi View está fuertemente tipada. Cuando Html.DropDownList ("UserId" se cambia a cualquier otro nombre excepto "UserId", el valor seleccionado se representa correctamente.
Sin embargo, esto hace que el valor no esté ligado al modelo.
Aún puede nombrar DropDown como "UserId" y aún así tener el enlace de modelo funcionando correctamente para usted.
El único requisito para que esto funcione es que la clave ViewData que contiene SelectList no tiene el mismo nombre que la propiedad del modelo que desea vincular. En su caso específico, esto sería:
// in my controller
ViewData["Users"] = new SelectList(
users,
"UserId",
"DisplayName",
selectedUserId.Value); // this has a value
// in my view
<%=Html.DropDownList("UserId", (SelectList)ViewData["Users"])%>
Esto producirá un elemento de selección que se llama UserId, que tiene el mismo nombre que la propiedad UserId en su modelo y, por lo tanto, el modelo de cuaderno lo configurará con el valor seleccionado en el elemento de selección del html generado por el helper Html.DropDownList.
No estoy seguro de por qué ese constructor Html.DropDownList en particular no seleccionará el valor especificado en la lista de selección cuando coloca la lista de selección en ViewData con una clave igual al nombre de la propiedad. Sospecho que tiene algo que ver con la forma en que se usa el asistente de DropDownList en otros escenarios, donde la convención es que usted tiene una Lista de selección en ViewData con el mismo nombre que la propiedad en su modelo. Esto funcionará correctamente:
// in my controller
ViewData["UserId"] = new SelectList(
users,
"UserId",
"DisplayName",
selectedUserId.Value); // this has a value
// in my view
<%=Html.DropDownList("UserId")%>
Así es como solucioné este problema:
Tenía lo siguiente:
Controlador:
ViewData["DealerTypes"] = Helper.SetSelectedValue(listOfValues, selectedValue) ;
Ver
<%=Html.DropDownList("DealerTypes", ViewData["DealerTypes"] as SelectList)%>
Modificado por lo siguiente:
Ver
<%=Html.DropDownList("DealerTypesDD", ViewData["DealerTypes"] as SelectList)%>
Parece que el DropDown no debe tener el mismo nombre que el nombre de ViewData: S extraño, pero funcionó.
El código en la publicación anterior de MVC 3 no funciona, pero es un buen comienzo. Yo lo arreglare. He probado este código y funciona en MVC 3 Razor C # Este código usa el patrón ViewModel para rellenar una propiedad que devuelve una List<SelectListItem>
.
La clase de modelo
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
}
La clase ViewModel
using System.Web.Mvc;
public class ProductListviewModel
{
public List<SelectListItem> Products { get; set; }
}
El método del controlador
public ViewResult List()
{
var productList = new List<SelectListItem>();
foreach (Product p in Products)
{
productList.Add(new SelectListItem
{
Value = p.ProductId.ToString(),
Text = "Product: " + p.Name + " " + p.Price.ToString(),
// To set the selected item use the following code
// Note: you should not set every item to selected
Selected = true
});
}
ProductListViewModel productListVM = new ProductListViewModeld();
productListVM.Products = productList;
return View(productListVM);
}
La vista
@model MvcApp.ViewModels.ProductListViewModel
@using (Html.BeginForm())
{
@Html.DropDownList("Products", Model.Products)
}
La salida de HTML será algo así como
<select id="Products" name="Products">
<option value="3">Product: Widget 10.00</option>
<option value="4">Product: Gadget 5.95</option>
</select>
dependiendo de cómo formatee la salida. Espero que esto ayude. El código funciona
El problema es que los buzones no funcionan igual que los cuadros de lista, al menos como espera el diseño de ASP.NET MVC2: un dropbox permite solo cero o un valor, ya que los listbox pueden tener una selección de valores múltiples. Entonces, al ser estricto con HTML, ese valor no debería estar en la lista de opciones como bandera "seleccionada", sino en la entrada misma.
Vea el siguiente ejemplo:
<select id="combo" name="combo" value="id2">
<option value="id1">This is option 1</option>
<option value="id2" selected="selected">This is option 2</option>
<option value="id3">This is option 3</option>
</select>
<select id="listbox" name="listbox" multiple>
<option value="id1">This is option 1</option>
<option value="id2" selected="selected">This is option 2</option>
<option value="id3">This is option 3</option>
</select>
El combo tiene la opción seleccionada, pero también tiene su atributo de valor establecido . Por lo tanto, si desea que ASP.NET MVC2 represente un dropbox y también tenga un valor específico seleccionado (es decir, valores predeterminados, etc.), debe darle un valor en el procesamiento, como este:
// in my view
<%=Html.DropDownList("UserId", selectListItems /* (SelectList)ViewData["UserId"]*/, new { @Value = selectedUser.Id } /* Your selected value as an additional HTML attribute */)%>
En ASP.NET MVC 3 puede simplemente agregar su lista a ViewData ...
var options = new List<SelectListItem>();
options.Add(new SelectListItem { Value = "1", Text = "1" });
options.Add(new SelectListItem { Value = "2", Text = "2" });
options.Add(new SelectListItem { Value = "3", Text = "3", Selected = true });
ViewData["options"] = options;
... y luego hacer referencia por su nombre en su vista de afeitar ...
@Html.DropDownList("options")
No tiene que "usar" manualmente la lista en la llamada DropDownList. Haciéndolo de esta manera, también establezca correctamente el valor seleccionado para mí.
Renuncia:
- No he intentado esto con el motor de vista de formularios web, pero debería funcionar también.
- No he probado esto en v1 y v2, pero podría funcionar.
Esto parece ser un error en la clase SelectExtensions, ya que solo verificará ViewData en lugar del modelo para el elemento seleccionado. Entonces, el truco es copiar el elemento seleccionado del modelo en la colección ViewData bajo el nombre de la propiedad.
Esto se toma de la respuesta que di en los foros de MVC, también tengo una respuesta más completa en una publicación de blog que usa el atributo DropDownList de Kazi ...
Dado un modelo
public class ArticleType
{
public Guid Id { get; set; }
public string Description { get; set; }
}
public class Article
{
public Guid Id { get; set; }
public string Name { get; set; }
public ArticleType { get; set; }
}
y un modelo de vista básico de
public class ArticleModel
{
public Guid Id { get; set; }
public string Name { get; set; }
[UIHint("DropDownList")]
public Guid ArticleType { get; set; }
}
Luego, escribimos una plantilla de editor DropDownList de la siguiente manera:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<script runat="server">
IEnumerable<SelectListItem> GetSelectList()
{
var metaData = ViewData.ModelMetadata;
if (metaData == null)
{
return null;
}
var selected = Model is SelectListItem ? ((SelectListItem) Model).Value : Model.ToString();
ViewData[metaData.PropertyName] = selected;
var key = metaData.PropertyName + "List";
return (IEnumerable<SelectListItem>)ViewData[key];
}
</script>
<%= Html.DropDownList(null, GetSelectList()) %>
Esto también funcionará si cambia ArticleType en el modelo de vista a SelectListItem, aunque tiene que implementar un convertidor de tipo según el blog de Kazi y registrarlo para obligar al enlazador a tratar esto como un tipo simple.
En su controlador, entonces tenemos ...
public ArticleController
{
...
public ActionResult Edit(int id)
{
var entity = repository.FindOne<Article>(id);
var model = builder.Convert<ArticleModel>(entity);
var types = repository.FindAll<ArticleTypes>();
ViewData["ArticleTypeList"] = builder.Convert<SelectListItem>(types);
return VIew(model);
}
...
}
Prueba esto:
public class Person {
public int Id { get; set; }
public string Name { get; set; }
}
Y entonces:
var list = new[] {
new Person { Id = 1, Name = "Name1" },
new Person { Id = 2, Name = "Name2" },
new Person { Id = 3, Name = "Name3" }
};
var selectList = new SelectList(list, "Id", "Name", 2);
ViewData["People"] = selectList;
Html.DropDownList("PeopleClass", (SelectList)ViewData["People"])
Con MVC RC2, obtengo:
<select id="PeopleClass" name="PeopleClass">
<option value="1">Name1</option>
<option selected="selected" value="2">Name2</option>
<option value="3">Name3</option>
</select>
Si no creemos que este es un error que el equipo debería solucionar, al menos MSDN debería mejorar el documento. La confusión realmente proviene del pobre 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 de selección. 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, también usará la publicación de nuevo en el mismo modelo de vista. Pero en muchos casos, realmente no seguimos esa suposición.
Usa el ejemplo de arriba,
public class Person {
public int Id { get; set; }
public string Name { get; set; }
}
Si seguimos la suposición, debemos 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 de nuevo, solo el valor seleccionado se publicará de nuevo, por lo que se supone que debe enviarse de nuevo a 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 SelectedPersonId del modelo debe contener el valor predeterminado de esa lista desplegable. Incluso si su Lista <SelectListItem> Personas ya configura el indicador Seleccionado para indicar cuál está seleccionado / predeterminado, el tml.DropDownList ignorará eso y reconstruirá su propio IEnumerable <SelectListItem> y configurará 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 realmente fue más allá, no solo trata de 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 selección original.
El problema es que, en muchos casos, realmente no lo usamos 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 los viewdata. 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 lista de selección original ya tiene una seleccionada, ¿por qué ignorarías eso?
Solo mis pensamientos.