2012-07-14 23 views
11

Hemos intentado que la plantilla de editor funcione con una propiedad dinámica, sin éxito. Tal vez alguno de ustedes puede ayudarnos.Asp.Net MVC 3 Editor para la propiedad dinámica

Aquí es más o menos nuestra clase:

public class Criterion 
{ 
    ... 
    public string Text { get; set; } 
    public dynamic Value { get; set; } 
    public Type Type { get; set; } 
    ... 
} 

Nuestro punto de vista de afeitar consigue un modelo containg una lista de secciones que cada uno contiene una lista de criterios en el mismo. (Tenemos estas informaciones en tiempo de ejecución.) Todos estos criterios se deben mostrar en modo de edición - en cuanto a su tipo real: (extracto)

@for (int i = 0; i < model.Sections.Count(); i++) 
{ 
    for (int j = 0; j < model.Sections[i].Criteria.Count(); j++) 
    { 
     var criterion = model.Sections[i].Criteria[j]; 
     var type = criterion.Type.Name; 
     var name = "Sections[" + i + "].Criteria[" + j + "].Value"; 
     var criterionDisplayName = criterion.Text; 
     <label for="[email protected](i)[email protected](j)__Value">@criterionDisplayName</label> 
     @Html.Editor(name, type) 
    } 
} 

Esto pantalla, por ejemplo, una casilla de verificación correctamente, pero que no utiliza el valor para establecer correctamente el estado de la casilla de verificación (marcada si el criterio.Valor es verdadero). Lo mismo ocurre con otros tipos, como ints. (Rellena el formulario correctamente después de una solicitud POST, pero eso es porque MVC usa un modelo temporal para recrear la entrada de los usuarios.)

Por mucho que lo hemos intentado e investigado: ¿Es posible usar el Editor? plantilla con propiedades del tipo dynamic? En caso afirmativo, ¿cómo podemos hacer que funcione? (No nos gustaría discernir de acuerdo con el tipo posible. Nos gustaría tener el marco MVC para usar la plantilla correcta del Editor en función del tipo real.)

Respuesta

15

La dinámica no encaja bien con ASP.NET MVC. Me recuerdan a ViewBag y odio ViewBag de las telas muy profundas de mi cuerpo. Entonces tomaría un enfoque diferente.

Tomemos por ejemplo el siguiente modelo:

public class Criterion 
{ 
    public string Text { get; set; } 
    public object Value { get; set; } 
} 

valor podría ser cualquier tipo que desea manejar.

Ahora usted podría tener un controlador que puebla este modelo:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     var model = new[] 
     { 
      new Criterion { Text = "some integer", Value = 2 }, 
      new Criterion { Text = "some boolean", Value = true }, 
      new Criterion { Text = "some string", Value = "foo" }, 
     }; 
     return View(model); 
    } 
} 

y luego una vista correspondiente:

@model IList<Criterion> 

@using (Html.BeginForm()) 
{ 
    for (int i = 0; i < Model.Count; i++) 
    { 
     <div> 
      @Html.LabelFor(x => x[i], Model[i].Text) 
      @Html.EditorFor(x => x[i].Value, "Criterion_" + Model[i].Value.GetType().Name) 
     </div> 
    } 

    <button type="submit">OK</button> 
} 

Ahora, para cada tipo que desea controlar se podría definir un editor correspondiente plantilla:

~/Views/Shared/EditorTemplates/Criterion_String.cshtml:

@model string 
@Html.TextBoxFor(x => x) 

~/Views/Shared/EditorTemplates/Criterion_Boolean.cshtml:

@model bool 
@Html.CheckBoxFor(x => x) 

~/Views/Shared/EditorTemplates/Criterion_Int32.cshtml:

@model int 
@{ 
    var items = Enumerable 
     .Range(1, 5) 
     .Select(x => new SelectListItem 
     { 
      Value = x.ToString(), 
      Text = "item " + x 
     }); 
} 

@Html.DropDownListFor(x => x, new SelectList(items, "Value", "Text", Model)) 

mostrando Obviamente este modelo en la vista es sólo el primer paso. Supongo que querrá obtener los valores que el usuario ingresó en la acción del controlador POST para algún procesamiento. En este caso, algunas pequeñas adaptaciones son necesarias. Necesitamos agregar un archivador de modelo personalizado que pueda instanciar el tipo correcto en tiempo de ejecución e incluir el tipo concreto como campo oculto para cada fila. Ya he mostrado un ejemplo en this post. También observe en este ejemplo que utilicé una clase base en lugar de trabajar directamente con el tipo object.

+0

Funciona con vista fuertemente tipada.Traté de cambiar la vista de índice para no usar la vista fuertemente tipada: eliminado '@model IList ' y utilizado '@ {var model = (IList ) Modelo; } ' Luego pruebo '@ Html.Editor (" modelo ["+ i +"] .Value "," Criterion_ "+ model [i] .Value.GetType(). Name)', pero me da un error - _El modelo el elemento pasado al diccionario es nulo, pero este diccionario requiere un elemento de modelo no nulo de tipo 'System.Int32' ._ ¿Qué estoy haciendo mal? La depuración me dice que GetType(). Name es 'Int32' en Index-View. – toni

+0

Por cierto, necesitamos usar la vista no fuertemente tipada, porque estamos usando un marco de terceros (ContentShape de Orchard). – toni

+0

Terminamos usando el enfoque Darins como el anterior con 'object'. Solo tuvimos que lanzar el modelo de vista dinámico y pasarlo a una plantilla de editor fuertemente tipada. Gracias, Darin, por la valiosa contribución. – toni