2012-04-12 14 views
6

Mi modelo es el siguiente:en el poste, una lista desplegable SelectList.SelectedValue es nulo

public class testCreateModel 
{ 
    public string s1 { get; set; } 
    public SelectList DL { get; set; } 

    public testCreateModel() 
    { 
     Dictionary<string, string> items = new Dictionary<string, string>(); 
     items.Add("1", "Item 1"); 
     items.Add("2", "Item 2"); 
     DL = new SelectList(items, "Key", "Value"); 
    } 
} 

Mi iniciación de las acciones es:

public ActionResult testCreate() 
    { 
     testCreateModel model = new testCreateModel(); 
     return View(model); 
    } 

Mi punto de vista Razor (partes irrelevantes borrados) es:

@model Tasks.Models.testCreateModel 

@using (Html.BeginForm()) { 
<fieldset> 
    <legend>testCreateModel</legend> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.s1) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.s1) 
    </div> 

    <div class="editor-label"> 
     Select an item: 
    </div> 
    <div class="editor-field"> 
     @Html.DropDownList("dropdownlist", (SelectList)Model.DL) 
    </div> 

    <p> 
     <input type="submit" value="Create" /> 
    </p> 
</fieldset> 
} 

La acción posterior a la espalda es:

public ActionResult testCreate(testCreateModel model, FormCollection collection) 
    { 
     if (ModelState.IsValid) 
     { 
      Console.WriteLine("SelectedValue: ",model.DL.SelectedValue); 
      Console.WriteLine("FormCollection:", collection["dropdownlist"]); 
      // update database here... 
     } 
     return View(model); 
    } 

En segundo palo, model.DL.SelectedValue es nulo. (Sin embargo, el elemento seleccionado se puede obtener de FormCollection, pero eso es además del punto). El objeto DL está siendo adecuadamente poblada de lo contrario, la salida inmediata de la ventana de la siguiente manera:

model.DL 
{System.Web.Mvc.SelectList} 
    base {System.Web.Mvc.MultiSelectList}: {System.Web.Mvc.SelectList} 
    SelectedValue: null 
model.DL.Items 
Count = 2 
    [0]: {[1, Item 1]} 
    [1]: {[2, Item 2]} 
model.DL.SelectedValue 
null 

P1: ¿Cómo se puede hacer uso de la propiedad SelectedValue en su lugar?

Ahora, si en la vista de la maquinilla de afeitar cambio el nombre de la etiqueta HTML SELECT para DL (es decir, mismo que el nombre de la propiedad en el modelo):

@Html.DropDownList("DL", (SelectList)Model.DL) 

consigo una excepción:

No parameterless constructor defined for this object. 
Stack Trace: 
[MissingMethodException: No parameterless constructor defined for this object.] 
System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0 
System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache) +98 
System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache) +241 
System.Activator.CreateInstance(Type type, Boolean nonPublic) +69 
System.Web.Mvc.DefaultModelBinder.CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) +199 
System.Web.Mvc.DefaultModelBinder.BindSimpleModel(ControllerContext controllerContext, ModelBindingContext bindingContext, ValueProviderResult 
... 

Q2: ¿Por qué?

Gracias.

Respuesta

11

MVC devolverá sólo el valor de la opción seleccionada en su puesto, por lo que necesita una propiedad para contener el único valor que devuelve.

Como un buen consejo, intente configurar SelectLists a través de ViewBag, que ayuda a mantener sus ViewModels limpios de los datos que necesitan rellenar el formulario.

Así que su ejemplo podría ser resuelto de esta manera:

public class testCreateModel 
{ 
    public string s1 { get; set; } 
    public int SelectedValue { get; set; } 
} 

y en su vista a hacer esto:

@Html.DropDownList("SelectedValue", (SelectList)ViewBag.DL) 

antes de poblar ViewBag.DL en su acción GET.

En cuanto a su Q2, el ModelBinder por defecto requiere que todos los tipos de obligar a tener un constructor por defecto (para que el ModelBinder puede crearlas)

+0

Gracias por el método sugerido para usar una lista desplegable. ¡Funciona y se necesita menos trabajo para recoger el valor seleccionado! –

+0

Gracias, esta es la mejor publicación que me heionado con respecto al uso de la lista desplegable en mvc –

10

Una respuesta ha sido seleccionado, pero mira cómo lo hice. A continuación se muestra el código de cómo lo hago normalmente cuando llene un menú desplegable. Es muy simplista, le sugiero que lo use como base para construir sus menús desplegables.

En la parte superior de mi vista que especifique mi vista del modelo:

@model MyProject.ViewModels.MyViewModel 

En mi opinión, tengo una lista desplegable que muestra todos los bancos que un usuario puede seleccionar:

<table> 
    <tr> 
      <td><b>Bank:</b></td> 
      <td> 
       @Html.DropDownListFor(
        x => x.BankId, 
        new SelectList(Model.Banks, "Id", "Name", Model.BankId), 
        "-- Select --" 
       ) 
       @Html.ValidationMessageFor(x => x.BankId) 
      </td> 
    </tr> 
</table> 

Siempre tengo un modelo de vista para una vista, nunca paso un objeto de dominio directamente a la vista. En este caso mi modelo de vista contendrá una lista de bancos que se rellena a partir de la base de datos:

public class MyViewModel 
{ 
    // Other properties 

    public int BankId { get; set; } 
    public IEnumerable<Bank> Banks { get; set; } 
} 

Mi modelo de dominio bancaria:

public class Bank 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

Luego, en mi método de acción que cree una instancia de mi ver el modelo y completar la lista de bancos desde la base de datos. Una vez hecho esto, devuelvo el modelo de vista a la vista:

public ActionResult MyActionMethod() 
{ 
    MyViewModel viewModel = new ViewModel 
    { 
      // Database call to get all the banks 
      // GetAll returns a list of Bank objects 
      Banks = bankService.GetAll() 
    }; 

    return View(viewModel); 
} 

[HttpPost] 
public ActionResult MyActionMethod(MyViewModel viewModel) 
{ 
    // If you have selected an item then BankId would have a value in it 
} 

Espero que esto ayude.

+0

Excelente y gracias por compartir. Sin embargo, tengo problemas para recuperar los datos en la devolución de datos del formulario. ¿Algunas ideas? Gracias –

Cuestiones relacionadas