Hace algunos días estaba con otro proyecto en MVC, y mientras trabajaba con un formulario se dio algo bastante extraño. Tenia un DropDownList al cual queria llenar con 3 opciones y sus correspondientes Valores de esta manera:
<select name="status" id="status"> <option value="E">Empty</option> <option value="F">Full</option> <option value="E/F" selected="selected">Empty/Full</option> </select>
En MVC cuando se necesita representar data en formularios de esta manera generalmente se utiliza un patrón ViewModel, una clase que se encarga de hacer el cambio de data pura (ids de BD) a algo entendible por el usuario por ejemplo yo como desarrollador se que el cogido “E” en BD representa Empty, pero el usuario puede no saberlo y no vamos a enviarle solo la letra E como opción en el DropDownList, asi que hay que hacer la traducción con un ViewModel.
Asi que cree una clase llamada EventViewModel con estas dos propiedades:
public Event Eventx { get; set; } public SelectList status { get; set; }
y un constructor que recibe como parámetro la data pura (que por lo general es un clase mapeda de una BD), y realiza los pases necesarios para realizar la traducción al construirse a si misma.
public EventViewModel(Event Event) { Eventx = Event == null ? new Event() : Event; status = new SelectList(pl, "value", "text", Event == null ? pl.First().value : Event.status.Trim()); }
status va a alojar mi objeto de tipo Selectlist que toma como parametros la lista pl, el nombre del elemento de la lista pl que actua como value del dropdown, (en mi caso casualmente también lo llame value), asi mismo el texto que sera el que el usuario vera desplegado y por ultimo el elemento que sera seleccionado por defecto, que como ven tiene un inline IF donde verifica el valor de Event (en mi caso si event es null es porque se trata de un Create Event) entonces simplemente selecciono el primero de la lista, en caso contrario selecciono la propiedad status del evento Event.
Con esto en su lugar podemos pasar a la vista y decirle:
<% = Html.DropDownList("status",Model.status)%>
Aquí Model es de tipo EventViewModel, y status de tipo SelectList así que en este punto todo debería funcionar, pero no es así..
El Problema..
Por alguna razón el DropDownList siempre aparece con el primer elemento seleccionado, sin importar lo que diga el SelectList(status), que deberia ser el que indique lo que debe o no estar seleccionado..
Entonces cual es el problema bueno si miramos la pequeña documentacion del helper DropDownList veremos que para el primer parametro string name dice:
The name of the form field and used as a key to look up possible options. If ViewData[name] Implements IEnumerable of System.Web.Mvc.SelectListItem
En pocas palabras el nombre que especifiques como primer parametro sera el name y id del elemento html generado y además sera la llave para buscar en el ViewData algun elemento de ese nombre que implemente IEnumerable of System.Web.Mvc.SelectListItem. Ahora no se si yo lo interpreto mal pero lo que no te dice es que ese mismo nombre sera utilizado para buscar el valor del selected Value para el DropDownList en el ViewData. Y este ultimo punto es el problema, ya que aunque no declaramos explicitamente un ViewData asi:
ViewData["status"]
Si tenemos una definición de ViewData.Model.status , que es donde alojamos el elemento SelectList(recordando que model es de tipo EventViewModel).
Eso quiere decir que cada vez que el DropDownList es generado busca algun elemento en el ViewData Con el nombre “status” y asume que el valor que aparezca aqui (sin importar el tipo que sea) sera el valor que debe aparecer seleccionando en el DropDownList, ignorando totalmente lo que dice el IEnumerable
Mi solución fue simplemente cambiar el nombre de la propiedad del EventViewModel de status a statusx, así el helper no tendrá mas opción que tomar el valor del modelo de tipo Model.statusx que le especifique explícitamente acá:
<% = Html.DropDownList("status",Model.statusx)%>
