繁体   English   中英

MVC局部视图中的多态ViewModel集合和渲染

[英]Polymorphic ViewModel collection and rendering in MVC partial Views

我的MVC应用程序中的ViewModel的多态集合存在问题。 我通过Web服务调用收到了这个,我需要迭代它们并根据对象类型给它们自己的局部视图。

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,以便我可以访问不同的属性。

我将如何以更优雅的方式解决这个问题? 我是否需要为抽象类创建一个新的代理基类来创建它的实例更容易?

您可以使用显示模板实现此目的。 在Controller的Views目录中的DisplayTemplates文件夹中为每种类型创建一个显示模板:

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

在视图中使用DisplayFor帮助器显示每个模型:

@model ICollection<ProvinceViewModel>

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

在遇到同样的问题时,我创建了以下解决方案:

首先,使用ExportMetadata属性装饰您的(具体)视图模型, ExportMetadata属性表示要使用的视图名称。 例如:

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

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

然后使用以下Partial方法扩展您的HtmlHelper

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

我有类似的要求,这就是我设法解决这个问题的方法。 我的viewmodel(BusinessEventEmailViewModel)有一个在运行时使用unity解析的接口列表(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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM