2011-01-10 13 views
5

Tengo una página web ASP.NET MVC 3 (Razor), y un modelo (simplificado) llamado revisión:ASP.NET MVC - Problema con EditorTemplate para ICollection <T> asignada a Enum

public class Review 
{ 
    public int ReviewId { get; set; } 
    public bool RecommendationOne 
    { 
     // hook property - gets/set values in the ICollection 
    } 
    public bool RecommendationTwo { // etc } 
    public ICollection<Recommendation> Recommendations { get; set; } 
} 

Recomendación es el siguiente:

public class Recommendation 
{ 
    public byte RecommendationTypeId 
} 

que también tienen una enumeración llamada RecommendationType, que utilizo para mapear la recomendación anterior a. (basado en RecommendationTypeId).

Entonces, para resumir - una sola revisión tiene muchas recomendaciones , y cada una de esas recomendaciones se asigna a un tipo de enumeración en particular, i exponen propiedades de gancho para simplificar vinculante modelo/código.

Por lo tanto, a la vista:

@Html.EditorFor(model => model.Recommendations, "Recommendations") 

bastante simple.

Ahora, para la plantilla del editor, quiero mostrar una casilla para cada posible RecommendationType (enum), y si el modelo tiene esa recomendación (por ejemplo, en la vista de edición), marque la casilla.

Esto es lo que tengo:

@model IEnumerable<xxxx.DomainModel.Core.Posts.Recommendation> 
@using xxxx.DomainModel.Core.Posts; 

@{ 
    Layout = null; 
} 

<table> 
    @foreach (var rec in Enum.GetValues(typeof(RecommendationType)).Cast<RecommendationType>()) 
    { 
     <tr> 
      <td> 
       @* If review contains this recommendation, check the box *@ 
       @if (Model != null && Model.Any(x => x.RecommendationTypeId == (byte)rec)) 
       { 
        @* How do i create a (checked) checkbox here? *@ 
       } 
       else 
       { 
        @* How do i created a checkbox here? *@ 
       } 

       @rec.ToDescription() 
      </td> 
     </tr> 
    } 
</table> 

Como sugiere el comentario - no sé cómo utilizar @Html.CheckBoxFor. Por lo general, toma una expresión basada en el modelo, pero estoy seguro de cómo enlazar a la propiedad del gancho en función del valor enum actualmente en bucle. Por ejemplo que tiene que hacer de forma dinámica @Html.CheckBoxFor(x => x.RecommendationOne), @Html.CheckBoxFor(x => x.RecommendationTwo), etc.

La solución actual que tengo (que trabaja), implica la construcción manualmente el <input> (incluyendo campos ocultos).

Pero como estoy empezando a utilizar las plantillas de editor, espero que alguien con experiencia me pueda señalar en una dirección "fuertemente tipada".

¿O existe una forma más agradable (HTML Helper) de hacer esto?

Respuesta

10

me gustaría empezar por la introducción de un modelo de vista adecuado para el escenario:

public enum RecommendationType { One, Two, Three } 

public class ReviewViewModel 
{ 
    public IEnumerable<RecommendationViewModel> Recommendations { get; set; } 
} 

public class RecommendationViewModel 
{ 
    public RecommendationType RecommendationType { get; set; } 
    public bool IsChecked { get; set; } 
} 

continuación, el controlador:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     // TODO: query the repository to fetch your model 
     // and use AutoMapper to map between it and the 
     // corresponding view model so that you have a true/false 
     // for each enum value 
     var model = new ReviewViewModel 
     { 
      Recommendations = new[] 
      { 
       new RecommendationViewModel { 
        RecommendationType = RecommendationType.One, 
        IsChecked = false 
       }, 
       new RecommendationViewModel { 
        RecommendationType = RecommendationType.Two, 
        IsChecked = true 
       }, 
       new RecommendationViewModel { 
        RecommendationType = RecommendationType.Three, 
        IsChecked = true 
       }, 
      } 
     }; 
     return View(model); 
    } 

    [HttpPost] 
    public ActionResult Index(ReviewViewModel model) 
    { 
     // Here you will get for each enum value the corresponding 
     // checked value 
     // TODO: Use AutoMapper to map back to your model and persist 
     // using a repository 
     return RedirectToAction("Success"); 
    } 
} 

y la vista correspondiente (~/Views/Home/Index.cshtml):

@model YourAppName.Models.ReviewViewModel 

@{ 
    ViewBag.Title = "Index"; 
} 

@using (Html.BeginForm()) 
{ 
    @Html.EditorFor(model => model.Recommendations) 
    <input type="submit" value="Go" /> 
} 

y finalmente la plantilla del editor (~/Views/Home/EditorTemplates/RecommendationViewModel.cshtml)

@model YourAppName.Models.RecommendationViewModel 
<div> 
    @Html.HiddenFor(x => x.RecommendationType) 
    @Model.RecommendationType 
    @Html.CheckBoxFor(x => x.IsChecked) 
</div> 

Ahora el código de la vista se limpia como debería.Sin Ifs, sin bucles, sin LINQ, sin reflexión, esta es la responsabilidad de la capa de controlador/mapeador. Por lo tanto, cada vez que se encuentre escribiendo alguna lógica avanzada de C# en su vista, le recomendaría que reconsidere sus modelos de vista y los adapte según sea necesario. Para eso están diseñados los modelos de visualización: para estar lo más cerca posible de la lógica de visualización.

+2

En serio, Darin, eres increíble. :) Esto se ve muy bien, voy a intentar esto y me pondré en contacto contigo. +1 por ahora. :) – RPM1984

+1

¡Funciona con encanto! – RPM1984

Cuestiones relacionadas