c# - 在 View 中显示从抽象基础派生的更多类型的最佳方式是什么?

标签 c# asp.net-mvc view abstract-base-class

例如我有这三个类:

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 View (或 WF 中的 GridView)中显示这些类。那么最好的方法是什么?如果我想添加编辑选项怎么办?

enter image description here

最佳答案

您可以在那种情况下使用显示模板

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

假设我们有以下 Controller 操作方法,它返回一个用于显示 AbstractBase 对象列表的 View :

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 文件夹中搜索合适的 View 。

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

您可以为基类中的字段创建另一个显示模板,~/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 之外,您的第一个也是最好的选择是手动将基类的模板呈现为分部 View 。该行将替换为 @Html.Partial("~/Views/Shared/DisplayTemplates/AbstractBase.cshtml", Model)

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

所以渲染 View 的主视图会做:

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

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

希望对您有所帮助!

关于c# - 在 View 中显示从抽象基础派生的更多类型的最佳方式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19110598/

相关文章:

带有 YUI 的 ASP.NET MVC

java - 无法从 PHP Mysql 检索图像

c# - 我应该用什么来传递参数? C# 中的列表/数组/对象

c# - 当 .NET 不在垃圾回收 (GC) 中间时,如何捕获 .NET 进程的进程内存转储

c# - .NET 中随机类实现的质量如何?

c# - Ajax 错误名称未解决

c# - 从图像中删除所有水平和垂直线

c# - MVC 模型绑定(bind) + 格式化

mysql - MySQL中的INDEX和VIEW有什么区别

postgresql - 如何在VIEWS中正确使用DISTINCT