2012-02-03 15 views
21

He estado atascado mucho tiempo para editar una subcolección de mi modelo, la colección del modelo era nula.Asp: net MVC 3: @ Html.Editor¿Para una subcolección de mi modelo en una plantilla?

finalmente he encontrado una solución, pero me resulta un poco sucio:

Primeros mis pruebas Datas:

objeto Modelo:

public class ContainerObject 
    { 
     public String Title { get; set; } 
     public List<ContainedObject> ObjectList { get; set; } 
    } 

Sub objeto de colección:

public class ContainedObject 
{ 
    public int Id { get; set; } 
    public String Text { get; set; } 
    public Boolean IsSelected { get; set; } 
} 

método controlador que generan el objeto

public ActionResult TestForm() 
    { 
     return View(new ContainerObject() 
     { 
      Title = "This is a sample title", 
      ObjectList = new List<ContainedObject>() 
       { 
        new ContainedObject(){Id=1, IsSelected = true, Text="ObjectOne"}, 
        new ContainedObject(){Id=2, IsSelected = false, Text="ObjectTwo"}, 
        new ContainedObject(){Id=3, IsSelected = true, Text="ObjectThree"}, 
        new ContainedObject(){Id=4, IsSelected = false, Text="ObjectFour"}, 
       } 
     }); 
    } 

controlador que recibe el objeto editado

[HttpPost] 
    public ActionResult TestFormResult(ContainerObject filledObject) 
    { 
     return View(); 
    } 

La vista

@model WebTestApplication.Models.ContainerObject 

@{ 
    ViewBag.Title = "TestForm"; 
} 
@using (Html.BeginForm("TestFormResult","Home", FormMethod.Post)){ 
    @Html.EditorFor(x => x.Title) 
    Html.RenderPartial("ContainedObject", Model.ObjectList); 
    <input type="submit" value="Submit"/> 
} 

El v parcial IEW (ContainedObject.cshtml)

@model IEnumerable<WebTestApplication.Models.ContainedObject> 
@{ 
    ViewBag.Title = "ContainedObject"; 
    int i = 0; 
} 
@foreach (WebTestApplication.Models.ContainedObject currentObject in Model) 
{ 
    <br /> 
    @Html.Label(currentObject.Text); 
    @Html.CheckBox("ObjectList[" + i + "].IsSelected", currentObject.IsSelected);                          
    @Html.Hidden("ObjectList[" + i + "].Id", currentObject.Id);                         
    @Html.Hidden("ObjectList[" + i + "].Text", currentObject.Text); 
    i++; 
} 

Esto realmente funciona, pero he un problema:

  • tengo para generar nombres de mí mismo y especificar la propiedad del objeto contenedor

Traté de usar Html.EditorFor en lugar de Html.RenderPartial en la vista, el problema es que me genera el nombre "Lista de objetos. [0] .Id" (con un adicional. entre el nombre de la propiedad y el descriptor de acceso).

También intenté usar solo @ Html.EditorFor en la vista parcial, pero creó vars con el nombre del objeto.

Si yo no uso ninguna plantilla, funciona:

@model WebTestApplication.Models.ContainerObject 

@{ 
    ViewBag.Title = "TestForm"; 
} 
@using (Html.BeginForm("TestFormResult", "Home", FormMethod.Post)) 
{ 
    @Html.EditorFor(x => x.Title) 
    for (int i = 0; i < Model.ObjectList.Count; i++) 
    { 
     <br /> 
     @Html.Label(Model.ObjectList[i].Text); 
     @Html.CheckBoxFor(m => Model.ObjectList[i].IsSelected); 
     @Html.HiddenFor(m => Model.ObjectList[i].Id); 
     @Html.HiddenFor(m => Model.ObjectList[i].Text); 
    } 

    <br /><input type="submit" value="Submit"/> 
} 

pero aquí es una simple plantilla, pero en mi caso real, que tendrá muchos más datos, y esto va a ser reutilizado tiempo múltiple Entonces, ¿cuál es mi mejor opción?

Respuesta

38

Puede simplificar su código al presentar EditorTemplate. Aquí es cómo:

  • La vista principal sigue siendo más o menos el mismo, excepto que sustituye renderPartial con EditorFor:

TestForm.cshtml

@model WebTestApplication.Models.ContainerObject 

@{ 
    ViewBag.Title = "TestForm"; 
    Layout = "~/Views/Shared/_Layout.cshtml"; 
} 

@using (Html.BeginForm("TestFormResult", "Home", FormMethod.Post)) { 
    @Html.EditorFor(m => m.Title) 
    @Html.EditorFor(m => m.ObjectList); 

    <input type="submit" value="Submit" /> 
} 
  • A continuación, cree una carpeta llamada EditorTemplates bajo Vistas/Inicio (asumiendo que su controlador es el hogar):

enter image description here

  • y agregue el siguiente plantilla para el ContainedObj ect:

ContainedObject.cshtml

@model WebTestApplication.Models.ContainedObject 

<p> 
    @Html.DisplayFor(m => m.Text) 
    @Html.CheckBoxFor(m => m.IsSelected) 
    @Html.HiddenFor(m => m.Id) 
    @Html.HiddenFor(m => m.Text) 
</p> 

El editor se repetirá de forma automática a través de la lista de objetos que hacen que el punto de vista de cada uno de ellos. Espero eso ayude.

+1

increíble! ¡No sabía que el editorFor o DisplayFor iteraran automáticamente si es una lista! ¿Hay alguna manera de hacerlo funcionar al especificar la plantilla que debe usar? – J4N

+0

Porque en hechos he tenido varias veces alguna información que se puede mostrar con casilla de verificación (selección múltiple) o con botón de radio (selección de un elemento), en el mismo controlador (por ejemplo, valor seleccionado y el valor predeterminado) – J4N

+0

Quiere especificar diferentes plantillas? Si es así, hay una sobrecarga para el Editor, que acepta el nombre de la plantilla. –

5

Encontré este hilo mientras buscaba algo más relacionado. Denis tiene la respuesta correcta, pero pensé que agregaría algo de sintaxis en caso de que alguien más se encuentre con esto:

Si tiene una plantilla de editor llamada "SomeTemplate.cshtml", puede usarla para una lista de elementos de la siguiente manera su punto de vista:

@for (var i = 0; i < Model.ObjectList.Count(); i++) 
{ 
    @Html.EditorFor(m => m.ObjectList[i], "SomeTemplate") 
} 

Luego, en el editor de plantillas:

@model WebTestApplication.Models.ContainedObject 

<br /> 
@Html.Label(Model.Text); 
@Html.CheckBoxFor(m => m.IsSelected); 
@Html.HiddenFor(m => m.Id); 
@Html.HiddenFor(m => m.Text); 
Cuestiones relacionadas