4

例如我有这三个类:

public abstract class AbstractBase 
{
    public int A { set; get; }
}

public class Derived1 : AbstractBase
{
    public int B { set; get; }
    public int C { set; get; }
}

public class Derived2 : AbstractBase
{
    public int D { set; get; }
}

以及一个返回列表的服务AbstractBase

public class AbstractBaseService
{
    public IEnumerable<AbstractBase> GetInstances()
    { 
        var results = new List<AbstractBase>();

        // TODO: Get data

        return results;
    }
}

我想在表中的强类型 ASP.NET MVC 视图(或 WF 中的 GridView)中显示这些类。那么最好的方法是什么?如果我想添加编辑选项怎么办?

在此处输入图像描述

4

1 回答 1

3

您可以在该场景中使用显示模板。

这个想法是为每个具体派生类型创建一个显示模板,并将在运行时确定列表中每个项目的特定类型的任务留给 MVC,然后选择适当的模板。

想象一下,我们有以下控制器操作方法,它返回一个用于显示 AbstractBase 对象列表的视图:

public ActionResult Foo()
{
    var list = new List<AbstractBase>()
    {
        new Derived1{ A = 1, B = 2, C = 3},
        new Derived2{ A = 1, D = 4},
    };
    return View(list);
}

您可以创建以下模板:

~/Views/Shared/DisplayTemplates/Derived1.cshtml

@model MvcApplication1.Models.Derived1
<td>
    @Html.DisplayFor(m => m.A)
</td>
<td>
    @Html.DisplayFor(m => m.B)
</td>
<td>
    @Html.DisplayFor(m => m.C)
</td>
<td></td>

~/Views/Shared/DisplayTemplates/Derived2.cshtml

@model MvcApplication1.Models.Derived2
<td>
    @Html.DisplayFor(m => m.A)
</td>
<td></td>
<td></td>
<td>
    @Html.DisplayFor(m => m.D)
</td>

不幸的是,当您想在表格中显示项目时,您需要为与每种具体类型不相关的列提供空的 tr 元素。

主视图~/Views/Home/Foo.cshtml将如下所示:

@model IEnumerable<MvcApplication1.Models.AbstractBase>           
<table>
    <thead>
        <tr>
            <th>Col A</th>
            <th>Col B</th>
            <th>Col C</th>
            <th>Col D</th>
        </tr>
    </thead>    
    <tbody>
        @foreach(var item in Model)
        {
            <tr>
                @Html.DisplayFor(m => item)
            </tr>
        }
    </tbody>
</table>

它获取一个 AbstractBase 对象列表并构建表的主体,遍历列表并为每个项目调用DisplayFor。MVC 将在运行时检查每个项目的具体类型,然后将在 DisplayTemplates 文件夹中搜索适当的视图。

这是最简单的方法,其中公共基类中的字段由每个具体派生类模板呈现。但是,为基类中的字段提供一个通用模板是有意义的。

您可以为基类中的字段创建另一个显示模板~/Views/Shared/DisplayTemplates/AbstractBase.cshtml

@model MvcApplication1.Models.AbstractBase
<td>
    @Html.DisplayFor(m => m.A)
</td>

如何调用通用基类中的字段模板取决于您是否使用 MVC 4。如果您使用的是 MVC 4,则可以从派生类的每个模板中调用基本模板。例如,Derived1 的模板将如下所示:

@model MvcApplication1.Models.Derived1
@Html.DisplayFor(m => m, "AbstractBase")
<td>
    @Html.DisplayFor(m => m.B)
</td>
<td>
    @Html.DisplayFor(m => m.C)
</td>
<td></td>

如果您不在 MVC 4 上,可悲的是嵌套显示编辑器不起作用,所以@Html.DisplayFor(m => m, "AbstractBase")上面的行不会做任何事情。

在 MVC4 之外,您的第一个也是最好的选择是手动将基类的模板呈现为局部视图。该行将替换为@Html.Partial("~/Views/Shared/DisplayTemplates/AbstractBase.cshtml", Model)

我建议您避免的另一个选择是将对抽象类模板的调用移动到主视图中,而不是从每个派生类模板中调用。如果基类的模板需要嵌入到每个派生类生成的某个元素中,这甚至可能不是一个有效的选项。例如,如果基类的列并非全部位于每行的开头(或结尾),则不会是一个选项

因此,呈现视图的主视图将执行以下操作:

@foreach(var item in Model)
{
    <tr>
        @Html.DisplayFor(m => item, "AbstractBase")
        @Html.DisplayFor(m => item)
    </tr>
}

我会一直坚持从每个派生模板中调用基本模板,如果你发现自己使用最后一种方法,我会说你应该非常小心。否则,您需要记住@Html.DisplayFor(m => item, "AbstractBase")每次要渲染派生模板时调用,并且某些 html 设计甚至可能无法使用该方法实现。

希望能帮助到你!

于 2013-10-01T12:48:23.047 回答