2011-11-15 15 views
5

¿Cómo puedo cerrar <tr> y abrir <tr> después de 3 iteraciones de bucle? Tengo MVC 3 en .NET 4.0. ¿Cómo puedo contar iteraciones de bucle en MVC 3?¿Cómo puedo contar los bucles en mvc3 en @foreach

Código actual:

@foreach (var articleOnFirstPage in Model.ArticlesOnFirstSite) 
{ 

<tr> 
    <td><div class="productsFrame"></div></td> 
</tr> 

} 

quiero conseguir esto:

<tr> 
     <td><div class="productsFrame"></div></td> 
     <td><div class="productsFrame"></div></td> 
     <td><div class="productsFrame"></div></td> 
    </tr> 
<tr> 
     <td><div class="productsFrame"></div></td> 
     <td><div class="productsFrame"></div></td> 
     <td><div class="productsFrame"></div></td> 
    </tr> 
<tr> 
     <td><div class="productsFrame"></div></td> 
     <td><div class="productsFrame"></div></td> 
     <td><div class="productsFrame"></div></td> 
    </tr> 
+3

Esta pregunta no tiene mucho sentido para mí. Si tiene 3 elementos en su objeto Model.ArticlesOnFirstSite, esto es exactamente lo que obtendrá. –

+0

¿Quieres tres loops en total o quieres tres loops para cada articleOnFirstPage? – Maess

+0

'Model.ArticlesOnFirstSite.Take (3)'? – asawyer

Respuesta

5

Usted puede realizar el siguiente pornografía en su opinión:

@model IEnumerable<Foo> 
<table> 
@foreach (var item in from i in Model.Select((value, index) => new { value, index }) group i.value by i.index/3 into g select g) 
{ 
    <tr> 
     @foreach (var x in item) 
     { 
      <td><div class="productsFrame">@x.SomeProperty</div></td> 
     } 
    </tr> 
} 
</table> 

o simplemente utilizar modelos de vista y hacer la agrupación en su acción de controlador que obviamente es lo que yo le recomendaría. El único hecho de que necesita hacer esto significa que su modelo de vista no está adaptado a los requisitos de su vista, es decir, agrupar los resultados por 3. Así que debe adaptarlo. No pase IEnumerable<Foo> a su vista. Pase IEnumerable<MyViewModel> donde, obviamente, MyViewModel contendrá la agrupación necesaria para que en sus vistas pueda simplemente hacer un bucle o como odio escribir para y para los bucles foreach en las vistas, simplemente use las plantillas de visualización. Que se hará cargo de todo y su punto de vista simplemente tener este aspecto:

<table> 
    @HtmlDisplayForModel() 
</table> 

se ve mejor que la pornografía inicial no es?


como se solicita en la sección de comentarios que aquí es como me gustaría implementar esto utilizando modelos de vista.

Como siempre en una ASP.NET MVC se inicia mediante la definición de los modelos de vista que reflejen los requisitos de su punto de vista (que repito son: mostrar una tabla con 3 columnas):

public class ItemViewModel 
{ 
    public string Title { get; set; } 
} 

public class MyViewModel 
{ 
    public IEnumerable<ItemViewModel> Items { get; set; } 
} 

continuación, usted pasa al controlador que llenará y pasar esta vista del modelo a la vista:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     // Obviously in a real world application the data is your domain model 
     // and comes from a repository or a service layer depending on the complexity 
     // of your application. I am hardcoding it here for the 
     // purposes of the demonstration 
     var data = Enumerable.Range(1, 30).Select(x => new { Title = "title " + x }); 

     var model = 
      from i in data.Select((value, index) => new { value, index }) 
      group i.value by i.index/3 into g 
      select new MyViewModel 
      { 
       Items = g.Select(x => new ItemViewModel { Title = x.Title }) 
      }; 

     return View(model); 
    } 
} 

y, finalmente, se escribe la vista correspondiente (~/Views/Home/Index.cshtml):

@model IEnumerable<MyViewModel> 
<table> 
    @Html.DisplayForModel() 
</table> 

y la ~/Views/Home/DisplateTemplates/MyViewModel.cshtml plantilla de visualización:

@model MyViewModel 
<tr> 
    @Html.DisplayFor(x => x.Items) 
</tr> 

y, finalmente, la plantilla ~/Views/Home/DisplateTemplates/ItemViewModel.cshtml pantalla correspondiente:

@model ItemViewModel 
<td>@Html.DisplayFor(x => x.Title)</td> 

y que es prácticamente todo. Simple, limpio, siguiendo buenas prácticas y convenciones.

Obviamente para llevar esto un paso más allá que introduciría AutoMapper para realizar el mapeo real entre sus modelos de dominio y los modelos de vista y el resultado final será con una solución muy elegante que se verá así:

public ActionResult Index() 
{ 
    IEnumerable<DomainModel> data = ... 
    var viewModel = Mapper.Map<IEnumerable<DomainModel>, IEnumerable<MyViewModel>>(data); 
    return View(viewModel); 
} 

o un paso más allá:

[AutoMap(typeof(IEnumerable<DomainModel>), typeof(IEnumerable<MyViewModel>))] 
public ActionResult Index() 
{ 
    IEnumerable<DomainModel> data = ... 
    return View(data); 
} 

Ahora estamos empezando a entrar en un asunto serio.

+0

Gracias por responder Darin. ¿Y cómo se vería como @HtmlDisplayForModel()? ¿Debo hacer esto en el control? – senzacionale

+1

@senzacionale, he actualizado mi respuesta para ilustrar eso con un ejemplo concreto que ilustra las prácticas por las que estoy predicando. –

+0

uu buen Darin. Gracias – senzacionale

5

La primera cosa que viene a la mente es better foreach loop

de Phil Haack Usándolo usted obtener un índice y puede úselo como

<ol> 
@Model.Each(@<li>Item @item.Index of @(Model.Count() - 1): @item.Item.Title</li>) 
</ol> 

Lo que estamos buscando específicamente debería ser algo como:

@Model.ArticlesOnFirstSite.Each(@<td><div class="productsFrame"></div></td>@(@item.Index % 3 == 0 ? "</tr><tr>" : "")) 
3

Algo como esto puede funcionar.

@{int i = 0;} 
@foreach (var articleOnFirstPage in Model.ArticlesOnFirstSite) 
{ 
    @if ((i++ % 3) == 0) { 
     @if (i != 1) { 
      @:</tr> 
     } 
     @:<tr> 
    } 

    @:<td><div class="productsFrame"></div></td> 
} 

@if (i != 0) { 
    @:</tr> 
} 

Y esta es una solución de fuerza bruta a su problema.

Como otros han sugerido y como sugiero, debe cambiar su metodología: utilizar modelos de vista, los elementos del grupo de 3.

sobre cómo utilizar correctamente el patrón modelo-vista-controlador se puede ver en la web. http://msdn.microsoft.com/en-us/library/gg416514(v=vs.98).aspx es un buen comienzo.

+0

Esto me lastima los ojos. –

+0

@DarinDimitrov sí, estoy de acuerdo contigo, debería usar modelos de vista. –

+0

Si está de acuerdo, ¿por qué está sugiriendo un código ilegible? Quiero decir que se ve horrible. Un purista como yo simplemente no podía aceptar ese código en una vista. Simplemente sugiera usar modelos de vista en este caso. Sería lo correcto. En realidad, eso es lo que hay que hacer en cada aplicación ASP.NET MVC :-) –

0

Al igual que los otros decían, el mejor y más bonita solución es probable que hacer la agrupación en el controlador, pero esto podría hacer el trabajo:

@for (int i = 0; i < Model.ArticlesOnFirstSite.Count; i += 3) 
{ 
    <tr> 
     @foreach (Article article in Model.ArticlesOnFirstSite.Skip(i).Take(3)) 
     { 
      <td>@article.Title</td> 
     } 
    </tr> 
} 
Cuestiones relacionadas