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

C# 泛型局部视图:如何将泛型类设置为模型?,c#,asp.net-mvc,generics,C#,Asp.net Mvc,Generics,我正在尝试在ASP.NETMVC应用程序中构建通用网格视图 让我用一些代码来解释: public interface ITrustGrid<T> { IPagedList<T> Elements { get; set; } IList<IColumn<T>> Columns { get; set; } IList<string> Headers { get; } } 公共接口ITrustGrid { IPage

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

让我用一些代码来解释:

public interface ITrustGrid<T>
{
    IPagedList<T> Elements { get; set; }
    IList<IColumn<T>> Columns { get; set; }
    IList<string> Headers { get; }
}
公共接口ITrustGrid { IPagedList元素{get;set;} IList列{get;set;} IList头文件{get;} } 这是一个类的接口,允许我在控制器中设置列和表达式

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

<% Html.RenderPartial("SimpleTrustGridViewer", ViewData["employeeGrid"] as TrustGrid<EmployeeInfoDTO>); %>
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ITrustGrid<T>>" %>

问题是我不知道如何使渲染网格的局部视图成为通用视图

换言之,我想把这个转变为:

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

变成这样:

<% Html.RenderPartial("SimpleTrustGridViewer", ViewData["employeeGrid"] as TrustGrid<EmployeeInfoDTO>); %>
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ITrustGrid<T>>" %>

=>如何以最简单的方式使局部视图通用

编辑:

我通过使用一个TrustGridBuilder解决了这个问题,它有一个公共的TrustGrid GetTrustGrid()方法,该方法返回一个非通用的TrustGrid。信任网格包含字符串而不是linq内容。因此,我在GetTrustGrid()方法中执行linq,并将字符串放入TrustGrid对象中


谢谢大家在正确的轨道上帮助我。

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

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

例如:

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
{
字符串DisplayText{get;set;}
字符串ImageUrl{get;set;}
字符串AltText{get;set;}
}
公共接口ITrustGrid,其中T:IDisplayModel
{    
IPagedList元素{get;set;}
IList列{get;set;}
IList头文件{get;}
}

当然,您的
IDisplayModel
会根据您想要的行为而有所不同。这将允许您将实现此基本接口的任何内容传递给此分部,以建立一般行为。

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

例如,我会使用一个非通用视图数据类和一个附加字段:

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

    Func<object, string> ElementRenderer { get; }
}
公共接口ITrustGrid{ IPagedList元素{get;set;} IList列{get;set;} IList头文件{get;} Func 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>
    <%
}
%>

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

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

@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;
var columns=新列表
{
新列(“全名”,e=>string.Format(“{0}{1}”,e.FirstName,e.name)),
新列(“检查日期”,e=>e.ExchangationDate.HasValue?string.Format(“{0}天前”,currentDate.Subtract(e.ExchangationDate.Value).days):“未知”)
};
var employeeGrid=newtrustgrid{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>


正如您所看到的,我的partial中的任何代码都不依赖于所使用的类型。所以我仍然认为有一个简单的解决方案。

嗯,我试过了,但没能想出如何把它转换成有用的东西。你几乎不能把它转换成有用的东西,但您仍然可以将其用作动态对象。您能给出一个如何实现反射解决方案的简短示例吗?添加了示例并将contol INERTIES属性更改为接受“ITrustGrid”希望这就是您想要的。谢谢,但我不喜欢这个解决方案,因为我必须让每个类都实现IDisplayModel接口。我更喜欢一个解决方案,在这个解决方案中,我可以在局部视图中添加一些东西,使其工作。也许我可以向ITrustGrid接口添加一个类型成员?目前我正在尝试类似的方法,但我对这种通用的东西很陌生:)你可以在视图中使用反射,让你的视图模型ITrustGrid,然后使用反射来确定类型,并相应地在局部视图中显示逻辑,但这会使视图比我更膨胀。祝你好运。啊,我搞不懂。。一直在尝试各种各样的东西,但都找不到模型的类型。我尝试将“Type”成员添加到我的接口中,但这也不起作用。由于您的分部不依赖于所使用的类型,您可以只使用Object吗?ITrustGrid?我得到“传入字典的模型项的类型为'Helpers.TrustGrid
1[LinqToSqExample.model.EmployeeInfoDTO]”,但此字典需要'Helpers.ITrustGrid
1[System.Object]'类型的模型项。”当使用TrustGridModel调用分部视图时,当我使用TrustGridModel调用分部视图时,如果我从TrustGrid上的ITrustGrid(具体类)继承,则得到与上面描述的相同的结果。如果我将我的TrustGrid继承更改为ITrustGrid,那么它对我有效。嗯,明天我会尝试。谢谢你的检查。