2015-04-09 3 views
5

У меня возникла проблема с полиморфной коллекцией ViewModels в моем приложении MVC. Я получил это через вызов веб-службы, и мне нужно пройти через них и дать им свой собственный частичный вид, основанный на типе объекта.Полиморфная коллекция и рендеринг ViewModel в MVC partial Views

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

public sealed class OntarioViewModel : ProvinceViewModel { } 

public sealed class QuebecViewModel : ProvinceViewModel {} 

На мой взгляд, я пытаюсь выполнить итерацию через них и назначить частичный вид. Мне нужно сделать много типов, чтобы заставить его работать. Если я попытаюсь переместить это в действие контроллера и передать абстрактный тип, я получу ошибку, чтобы мы не могли создать экземпляр абстрактного класса.

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

У меня есть сильный тип View, так что я могу получить доступ к различным свойствам.

Как я могу решить это более элегантным способом? Нужно ли мне создать новый суррогатный базовый класс для абстрактного класса, чтобы создать экземпляр этого элемента проще?

+0

вы могли бы иметь 'ProvinceDetail' страница вместо этого вместо этого нужно переходить на разные провинции?Это позволит вам сохранить логику на этой странице, вместо того, чтобы повторять ее, если вы используете их в другом месте. – DLeh

+1

Это неясно: вам нужно создать экземпляр частичного вида для каждого * конкретного типа * RegionDetail или каждого * экземпляра * ? Кажется странным, что у вас будет несколько частичных представлений QuebecDetail, например. – Kjata30

+0

Извините, я попытался упростить пример. Мне нужно создать частичное представление для каждой провинции, которая имеет несколько разных свойств. например, Онтарио, Квебек, Манитоба, Британская Колумбия, все имеют конкретное и различное частичное представление, все остальное получает стандартный общий общий вид, т.е. ProvinceDetail. Результатом будет список провинций и их детали на главной странице. – mflair2000

ответ

0

У меня было аналогичное требование, и именно так мне удалось решить эту проблему. Моя модель просмотра (BusinessEventEmailViewModel) имеет список интерфейсов (IBusinessEventEmail), разрешенных во время выполнения с единством. IBusinessEventEmail имеет свойство EventCode.

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

На мой взгляд, я сделать частичное представление с помощью именовании:

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

Тогда у меня есть XXXEventEmail реализации IBusinessEventEmail с EventCode XXX и частичный вид _XXX.cshtml

1

При столкновении с той же проблемой в прошлом я создал следующее решение:

Сначала украсьте вашу (конкретную) модель вида ExportMetadata, который обозначает имя вида, которое будет использоваться. Например:

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

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

Затем продлить вашу HtmlHelper со следующим Partial способом:

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

Затем использовать:

@Html.Partial(currentProvince); 

И в случае, если ваш обертоны находятся в некотором подкаталоге:

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

(Если вам нужна помощь в регистрации пользовательского HTML-помощника, см. https://stackoverflow.com/a/5052790)

0

Вы можете достичь этого с помощью шаблонов дисплеев. Создание шаблона отображения для каждого типа в папке DisplayTemplates в вашей Views директории контроллера:

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

Дисплей каждой модели с помощью помощника Displayfor на ваш взгляд:

@model ICollection<ProvinceViewModel> 

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