2015-04-09 17 views
5

Mam problem z polimorficzną kolekcją ViewModels w mojej aplikacji MVC. Otrzymałem to poprzez wywołanie usługi internetowej i muszę iterować przez nie i dać im własny widok częściowy, w oparciu o typ obiektu.Polimorficzne ViewModel kolekcja i rendering w częściowych widokach MVC

public abstract class ProvinceViewModel 
{ 
    public string Code { get; set; } 
} 

public sealed class OntarioViewModel : ProvinceViewModel { } 

public sealed class QuebecViewModel : ProvinceViewModel {} 

Moim zdaniem próbuję iterować i przypisywać częściowy widok. Muszę wykonać wiele rzutowania typu, aby to działało. Jeśli spróbuję przenieść to do akcji kontrolera i przekazać typ abstrakcyjny, otrzymam błąd, że nie możemy utworzyć instancji klasy abstrakcyjnej.

ICollection<ProvinceViewModel> ProvinceList; // collection receive via service 

@for (int i = 0, c = ProvinceList.Count; i < c; i++) 
{ 
    var currentProvince = this.Model.ElementAt(i); 
    @switch (additionalRegistry.Code) 
    { 
     case "QC": 
      @Html.Partial("AlbertaDetail", (QuebecViewModel)currentProvince) 
      break;        
     case "ON": 
      @Html.Partial("OntarioDetail", (OntarioViewModel)currentProvince) 
      break; 
     default: 
      @Html.Partial("ProvinceDetail", ProvinceViewModel) 
      break; 
    } 
} 

Mam zdecydowanie typu Widok, aby uzyskać dostęp do różnych właściwości.

Jak mógłbym rozwiązać ten problem w bardziej elegancki sposób? Czy muszę utworzyć nową zastępczą klasę podstawową dla klasy abstrakcyjnej, aby łatwiej utworzyć taką instancję?

+0

można mieć 'stronę ProvinceDetail' zrobienia zamiast tego zamiast tego traktować różne prowincje?To pozwoliłoby ci zachować logikę na tej stronie, zamiast powtarzać ją, jeśli używasz ich gdzie indziej. – DLeh

+1

To nie jest jasne: czy musisz utworzyć instancję częściowego widoku dla każdego * konkretnego typu * Prowincji regionalnej lub każdego * tworzenia instancji * ? Wydaje się dziwne, że na przykład masz kilka częściowych widoków QuebecDetail. – Kjata30

+0

Przepraszamy, próbowałem uprościć przykład. Potrzebuję utworzyć wystąpienie częściowego widoku dla każdej prowincji, która ma różne właściwości. na przykład Ontario, Quebec, Manitoba, BC wszystkie mają określony i inny częściowy widok, wszystko inne dostaje standardowy domyślny widok ogólny, tj. ProvinceDetail. Rezultatem będzie lista prowincji i ich szczegóły na stronie głównej. – mflair2000

Odpowiedz

0

Miałem podobny wymóg i tak udało się rozwiązać ten problem. Mój viewmodel (BusinessEventEmailViewModel) ma listę interfejsów (IBusinessEventEmail) rozwiązanych w środowisku wykonawczym z jednością. Obiekt IBusinessEventEmail ma właściwość EventCode.

public class BusinessEventEmailViewModel : MailHeaderViewModel 
{ 
    #region members 
    public List<IBusinessEventEmail> Events { get; set; } 

Moim zdaniem renderować częściowego widoku przy użyciu konwencji nazewnictwa:

Html.RenderPartial("~/Views/Shared/Email/_" + businessEvent.EventCode + ".cshtml", businessEvent); 

Następnie mam XXXEventEmail realizacji IBusinessEventEmail z EventCode XXX i częściowym widokiem _XXX.cshtml

1

Po napotkaniu tego samego problemu w przeszłości, stworzyłem następujące rozwiązanie:

Po pierwsze, udekoruj swój (betonowy) model widoku za pomocą ExportMetadata atrybut, który oznacza nazwę widoku, który ma być użyty. Na przykład:

[ExportMetadata("View", "Ontario")] 
public sealed class OntarioViewModel : ProvinceViewModel { } 

[ExportMetadata("View", "Quebec")] 
public sealed class QuebecViewModel : ProvinceViewModel {} 

Następnie przedłużyć swój HtmlHelper z następującym Partial metody:

public static MvcHtmlString Partial<T>(this HtmlHelper htmlHelper, T model, string prefix = null) 
{ 
    var modelType = typeof (T); 
    var partialAttr = modelType.GetCustomAttributes<ExportMetadataAttribute>().SingleOrDefault(x => x.Name == "View"); 

    if (partialAttr == null) 
     throw new Exception(modelType.Name + " doesn't define any view to be used"); 

    var partialName = (prefix ?? String.Empty) + partialAttr.Value; 

    return htmlHelper.Partial(partialName, model, htmlHelper.ViewData); 
} 

Następnie użyj go:

@Html.Partial(currentProvince); 

A w przypadku, gdy partials przebywania w jakimś podkatalogu:

@Html.Partial(currentProvince, "Partials/") 

(Jeśli potrzebujesz pomocy w zarejestrowaniu niestandardowego pomocnika HTML, zobacz: https://stackoverflow.com/a/5052790)

0

Możesz to osiągnąć dzięki szablonom wyświetlania. Tworzenie szablonu wyświetlania dla każdego typu w folderze DisplayTemplates w kontrolerze za widoków katalogu:

+-- Views 
    +-- Provinces 
     +-- DisplayTemplates 
      +-- OntarioViewModel.cshtml 
      +-- QuebecViewModel.cshtml 

reklamowej każdy model używając pomocnika Displayfor w widoku:

@model ICollection<ProvinceViewModel> 

@foreach (var province in Model) 
{ 
    @Html.DisplayFor(_ => province) 
} 
Powiązane problemy