Polymorphic ViewModel collection and rendering in MVC partial Views

折月煮酒 提交于 2020-01-14 08:07:47

问题


I'm having a problem with a polymorphic collection of ViewModels in my MVC application. I received this via a web service call and i need to iterate through them and give them their own partial view, based on the object type.

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

public sealed class OntarioViewModel : ProvinceViewModel { }

public sealed class QuebecViewModel : ProvinceViewModel {}

In my view i am trying to iterate through them and assign a partial view. I have to do a lot of type casting here to make it work. If I try and move this to a controller action and pass in the abstract type, i will get an error that we cannot create an instance of abstract class.

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

I have strongly type View, so that i can access the different properties.

How would i go about solving this in a more elegant way? Would I need to create a new surrogate base class for the abstract class to create a instance of it easier?


回答1:


You can achieve this with display templates. Create a display template for each type in the DisplayTemplates folder within your Controller's Views directory:

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

Display each model using the DisplayFor helper in your view:

@model ICollection<ProvinceViewModel>

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



回答2:


Upon encountering the same problem in the past, I have created the following solution:

First, decorate your (concrete) view-model with ExportMetadata attribute that denotes the view name to be used. For example:

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

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

Then extend your HtmlHelper with the following Partial method:

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

Then use it:

@Html.Partial(currentProvince);

And in case your partials reside in some sub-directory:

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

(If you need help registering the custom HTML helper see https://stackoverflow.com/a/5052790)




回答3:


I had a similar requirement and this is how I managed to solve this issue. My viewmodel (BusinessEventEmailViewModel ) has a list of interfaces (IBusinessEventEmail) resolved at runtime with unity. A IBusinessEventEmail has an EventCode property.

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

In my view, I render the partial view using a naming convention :

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

Then, I have a XXXEventEmail implementing IBusinessEventEmail with the EventCode XXX and a partial view _XXX.cshtml



来源:https://stackoverflow.com/questions/29542850/polymorphic-viewmodel-collection-and-rendering-in-mvc-partial-views

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!