通用局部视图:如何将泛型类设置为模型?

时间:2009-05-17 17:45:36

标签: c# asp.net-mvc generics

我正在尝试在ASP.NET MVC应用程序中构建通用网格视图。

让我用一些代码解释一下:

public interface ITrustGrid<T>
{
    IPagedList<T> Elements { get; set; }
    IList<IColumn<T>> Columns { get; set; }
    IList<string> Headers { get; }
}

这是一个类的接口,允许我在控制器中设置列和表达式。

我将实现传递给部分视图,如下所示:

<% Html.RenderPartial("SimpleTrustGridViewer", ViewData["employeeGrid"] as TrustGrid<EmployeeInfoDTO>); %>

问题在于我无法弄清楚如何制作呈现网格通用的局部视图。

换句话说,我想转此:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ITrustGrid<EmployeeInfoDTO>>" %>

这样的事情:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ITrustGrid<T>>" %>

=&GT;如何以最简单的方式使我的部分视图通用?

修改

我通过使用具有公共TrustGrid GetTrustGrid()方法的TrustGridBuilder解决了这个问题,该方法返回非通用的TrustGrid。 TrustGrid包含字符串而不是linq的东西。所以我在GetTrustGrid()方法中执行linq并将字符串放在TrustGrid对象中。

感谢大家帮助我走上正轨。

4 个答案:

答案 0 :(得分:7)

您可以将您传递给此部分继承的所有模型类型从基类/接口继承,该基类/接口建立此部分视图将使用的基本行为并接受该类/接口类型的任何对象,或者只是让视图接受任何类型的对象,然后使用反射将您的部分视图行为基于。

实施例

public interface IDisplayModel
{
    string DisplayText{get;set;}
    string ImageUrl{get;set;}
    string AltText{get;set;}
}

public interface ITrustGrid<T> where T : IDisplayModel
{    
    IPagedList<T> Elements { get; set; }    
    IList<IColumn<T>> Columns { get; set; }    
    IList<string> Headers { get; }
}

<%@ Control Language="C#" 
    Inherits="System.Web.Mvc.ViewUserControl<ITrustGrid<IDisplayModel>>" %>

当然,您的IDisplayModel会因您所希望的行为而异。这将允许您将任何内容传递给实现此基本接口的部分以建立一般行为。

答案 1 :(得分:5)

这样做是不可能的。原因是.aspx将生成一个您没有太多控制权的类,并且您无法向其添加泛型参数。我想最直接的方法是将其作为object传递。

答案 2 :(得分:1)

我同意Mehrdad,据我所知,不可能制作通用视图。在我的一个项目中,我使用了一个非常类似的接口,然后将委托函数传递给处理每个项目的特定呈现的视图。

例如,我会使用带有附加字段的非泛型视图数据类:

public interface ITrustGrid {
    IPagedList Elements { get; set; }
    IList<IColumn> Columns { get; set; }
    IList<string> Headers { get; }

    Func<object, string> ElementRenderer { get; }
}

在主视图中,您将准备视图数据:

<%
ITrustGrid data = (ITrustGrid)ViewData["employeeGrid"];
data.ElementRenderer = new Func<object, string>(delegate(o) {
    var employee = (Employee)o;
    //render employee
    return html;
});

Html.RenderPartial("SimpleTrustGridViewer", data);
%>

在你的网格中,你会像往常一样处理网格,然后调用委托来渲染每个单元格:

<%
foreach(var element in ViewData.Elements){
    %>
    <tr>
        <td><%=ViewData.ElementRenderer(element) %></td>
    </tr>
    <%
}
%>

当然,上面的代码只为每个元素呈现一个单元格,您必须创建一个稍微复杂的委托来呈现多个列(或传入一个委托数组,每列一个)。 p>

我认为这是最干净的方法之一,虽然有点麻烦。

答案 3 :(得分:0)

@Lck:

我在我的控制器中做了类似的事情:

var columns = new List<IColumn<EmployeeInfoDTO>>
                  {
                      new Column<EmployeeInfoDTO>("Full name", e => string.Format("{0} {1}", e.FirstName, e.Name)),
                      new Column<EmployeeInfoDTO>("Examination date", e => e.ExaminationDate.HasValue? string.Format("{0} days ago", currentDate.Subtract(e.ExaminationDate.Value).Days) : "Unknown")
                  };

var employeeGrid = new TrustGrid<EmployeeInfoDTO> { Columns = columns, Elements = GetEmployees(currentPageIndex)};

ViewData["employeeGrid"] = employeeGrid;

因此,在我的部分视图中,我可以这样做:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ITrustGrid<EmployeeInfoDTO>>" %>
<table>
    <thead>
        <tr>
            <%
                foreach (string header in Model.Headers)
                    Response.Write(Html.Th(header));
            %>
        </tr>
    </thead>
    <tbody>
        <%
            foreach (var element in Model.Elements)
            {
                Response.Write("<tr>");
                foreach (var column in Model.Columns)
                    Response.Write(Html.Td(column.ValueExpression(element)));
                Response.Write("</tr>");
            }
        %>
    </tbody>
</table>
<div class="pager">
    <%= Html.Pager(Model.Elements.PageSize, Model.Elements.PageNumber, Model.Elements.TotalItemCount)%>
</div>

如您所见,我的部分代码中没有任何代码取决于所使用的类型。所以我仍然认为这是一个简单的解决方案。