2011-11-15 14 views
5

Come posso chiudere <tr> e aprire <tr> dopo 3 iterazioni di ciclo? Ho MVC 3 in .NET 4.0. Come posso contare le iterazioni di loop in MVC 3?Come posso contare i loop in mvc3 in @foreach

Codice attuale:

@foreach (var articleOnFirstPage in Model.ArticlesOnFirstSite) 
{ 

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

} 

voglio ottenere questo:

<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

Questa domanda non ha molto senso per me. Se hai 3 articoli nell'oggetto Model.ArticlesOnFirstSite, questo è esattamente ciò che otterrai. –

+0

Vuoi tre cicli in totale o vuoi tre loop per ogni articoloOnFirstPage? – Maess

+0

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

risposta

5

è possibile eseguire il seguente pornografia nella vista:

@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 semplicemente utilizzare modelli vista e fare il raggruppamento nella vostra azione di controllo che ovviamente è quello che mi sento di raccomandare voi. Il solo fatto che devi fare questo significa che il tuo modello di visualizzazione non è adattato alle esigenze della tua vista, ovvero raggruppare i risultati per 3. Quindi adattarlo. Non passare IEnumerable<Foo> alla tua vista. Passa al numero IEnumerable<MyViewModel> dove ovviamente MyViewModel conterrà il raggruppamento necessario in modo tale che nelle tue visualizzazioni potresti semplicemente eseguire il ciclo o poiché non riesco a scrivere e forare i cicli nelle viste semplicemente usando i modelli di visualizzazione. Si prenderanno cura di tutto e la visualizzazione semplicemente simile a questa:

<table> 
    @HtmlDisplayForModel() 
</table> 

sembra migliore rispetto al pornografia iniziale non è vero?


Come richiesto nella sezione commenti qui come vorrei implementare questo utilizzando modelli di visualizzazione.

come sempre in un ASP.NET applicazione MVC si inizia definendo i modelli vista che riflettano le esigenze della vostra vista (che ripeto sono: mostrare una tabella con 3 colonne):

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

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

poi si passa al controller che riempirà e passare questo modello prospettiva della 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); 
    } 
} 

e infine si scrive la vista corrispondente (~/Views/Home/Index.cshtml):

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

e ~/Views/Home/DisplateTemplates/MyViewModel.cshtml modello di visualizzazione:

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

e, infine, il corrispondente modello ~/Views/Home/DisplateTemplates/ItemViewModel.cshtml visualizzazione:

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

e che è praticamente. Semplice, pulito, seguendo le buone pratiche e le convenzioni.

Ovviamente per portare questo un ulteriore passo avanti che ci si introdurrà AutoMapper per eseguire la mappatura reale tra il modelli di dominio e visualizzare modelli e si finirà con una soluzione molto elegante, che sarà simile a questa:

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

o un ulteriore passo:

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

Ora stiamo iniziando a fare affari seri.

+0

per risposta Darin. E come sarebbe @HtmlDisplayForModel()? Devo farlo in controler? – senzacionale

+1

@senzacionale, ho aggiornato la mia risposta per illustrare ciò con un esempio concreto che illustra le pratiche per le quali predico. –

+0

caro Darin. Grazie – senzacionale

5

La prima cosa che viene in mente è di Phil Haack better foreach loop

Con esso si ottenere un indice e possono usalo come

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

Quello che stai specificamente alla ricerca di dovrebbe essere qualcosa di simile:

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

Qualcosa di simile può funzionare.

@{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> 
} 

E questa è una soluzione di forza bruta al problema.

Come altri hanno suggerito e come da me suggerito, si dovrebbe modificare la metodologia di: utilizzare la vista modelli, raggruppare gli elementi per 3.

A proposito di come utilizzare correttamente pattern Model-View-Controller si può guardare sul web. http://msdn.microsoft.com/en-us/library/gg416514(v=vs.98).aspx è un buon inizio.

+0

Questo mi fa male agli occhi. –

+0

@DarinDimitrov si, sono d'accordo con te, dovrebbe usare i modelli di vista. –

+0

Se sei d'accordo, perché stai suggerendo un codice così illeggibile? Intendo che sembra orribile. Un purista come me semplicemente non poteva accettare tale codice in una vista. Consigliamo semplicemente di utilizzare i modelli di visualizzazione in questo caso. Sarebbe la cosa giusta da fare. In realtà questa è la cosa giusta da fare in ogni applicazione ASP.NET MVC :-) –

0

Come gli altri ha detto, la soluzione migliore e più bella è probabilmente a che fare il raggruppamento nel controller, ma questo potrebbe ottenere il lavoro fatto:

@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> 
} 
Problemi correlati