2011-11-15 12 views
5

Jak mogę zamknąć <tr> i otworzyć <tr> po 3 pętli iteracji? Mam MVC 3 w .NET 4.0. Jak mogę liczyć iteracje pętli w MVC 3?Jak mogę policzyć pętle w mvc3 w @foreach

Aktualny Kod:

@foreach (var articleOnFirstPage in Model.ArticlesOnFirstSite) 
{ 

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

} 

chcę uzyskać to:

<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

To pytanie tak naprawdę nie ma dla mnie sensu. Jeśli masz 3 przedmioty w swoim obiekcie Model.ArticlesOnFirstSite, to właśnie to otrzymasz. –

+0

Chcesz trzy pętle łącznie, lub chcesz trzy pętle dla każdej articleOnFirstPage? – Maess

+0

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

Odpowiedz

5

Można wykonać następujące pornografii w widoku:

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

lub po prostu korzystać z widoku modeli i zrobić grupowanie w akcji kontrolera, który oczywiście jest to, co chciałbym Ci polecić. Sam fakt, że musisz to zrobić, oznacza, że ​​twój model widoku nie jest dostosowany do wymagań twojego widoku, czyli do grupowania wyników przez 3. Tak więc dostosuj go. Nie należy przekazywać IEnumerable<Foo> do widoku. Zdać IEnumerable<MyViewModel>, gdzie oczywiście MyViewModel będzie zawierał niezbędne grupowanie, tak aby w twoich widokach można było po prostu zapętlić lub ponieważ nienawidzę pisać i pętli foreach w widokach po prostu używaj szablonów wyświetlania. Zajmą się wszystkim, a Twój widok będzie wyglądał tak:

<table> 
    @HtmlDisplayForModel() 
</table> 

Wygląda lepiej niż początkowa pornografia, prawda?


Zgodnie z prośbą w sekcji komentarzy tutaj, w jaki sposób mogę to zaimplementować przy użyciu modeli widoku.

Jako zawsze w ASP.NET aplikacji MVC zacząć od zdefiniowania widoku modeli, które odzwierciedlają wymagania widoku (co powtarzam to: pokaż tabelę z 3 kolumnami):

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

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

następnie przenieść się do kontrolera, który wypełni i zdać ten widok modelu do widoku:

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); 
    } 
} 

i wreszcie napisać odpowiedni widok (~/Views/Home/Index.cshtml):

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

i ~/Views/Home/DisplateTemplates/MyViewModel.cshtml wyświetlacz szablon:

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

i wreszcie odpowiedni szablon ~/Views/Home/DisplateTemplates/ItemViewModel.cshtml display:

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

i to dość dużo. Proste, czyste, zgodne z dobrymi praktykami i konwencjami.

Oczywiście, aby doprowadzić ten krok dalej byś wprowadzenia AutoMapper przeprowadzić rzeczywiste odwzorowanie pomiędzy swoimi model domeny i widoków modeli i będzie skończyć z bardzo eleganckie rozwiązanie, które będzie wyglądać następująco:

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

lub krok dalej:

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

Teraz zaczynamy się poważnie interesować.

+0

thx za odpowiedź Darin. A jak wyglądałby @HtmlDisplayForModel()? Czy muszę to zrobić w kontrolerze? – senzacionale

+1

@senzacionale, zaktualizowałem swoją odpowiedź, aby zilustrować to konkretnym przykładem ilustrującym praktyki, o których nauczam. –

+0

uu miły Darin. Dzięki – senzacionale

5

Pierwszą rzeczą, która przychodzi do głowy jest Phil Haack na better foreach loop

Używając go można zdobyć indeks i może użyj go tak, jak

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

czego konkretnie szuka powinno być coś takiego:

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

Coś jak to może działać.

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

To jest brutalne rozwiązanie problemu.

Jako inny sugerowali, jak sugeruję, należy zmienić metodologię: użyj widoku modele, przedmioty grupowych przez 3.

o tym, jak prawidłowo używać wzorca Model-View-Controller można szukać w internecie. http://msdn.microsoft.com/en-us/library/gg416514(v=vs.98).aspx to dobry początek.

+0

To sprawia, że ​​moje oczy bolą. –

+0

@DarinDimitrov tak, zgadzam się z tobą, powinien używać modeli widoku. –

+0

Jeśli zgadzasz się, dlaczego sugerujesz taki nieczytelny kod? Mam na myśli, że wygląda okropnie. Purystka taka jak ja po prostu nie mogła zaakceptować takiego kodu w widoku. Po prostu sugeruj użycie modeli widoku w tym przypadku. Byłoby to słuszne. Właściwie to jest właściwe robić w każdej aplikacji ASP.NET MVC :-) –

0

Jak inni powiedział, najlepszym i najładniejszym rozwiązaniem jest prawdopodobnie zrobić grupowanie w sterowniku, ale to może to zadanie:

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