Общий частичный вид: как установить общий класс в качестве модели?
Я пытаюсь построить общий вид сетки в приложении 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>>" %>
=> Как я могу сделать мой частичный вид универсальным наиболее простым способом?
РЕДАКТИРОВАТЬ:
Я решил это с помощью TrustGridBuilder, который имеет публичный метод TrustGrid GetTrustGrid(), который возвращает неуниверсальный TrustGrid. TrustGrid содержит строки вместо linq. Поэтому я выполняю linq в методе GetTrustGrid () и помещаю строки в объект TrustGrid.
Спасибо всем, кто помог мне на правильном пути.
4 ответа
Это невозможно сделать так. Причина в том, что .aspx
создаст класс, который вы не можете контролировать, и вы не сможете добавить к нему универсальный параметр. Я думаю, что самый простой способ - передать его как object
,
Вы можете сделать все свои типы моделей, которые вы передадите в это частичное наследование, базовым классом / интерфейсом, который устанавливает базовое поведение, которое будет использоваться этим частичным представлением, и принять любой объект этого класса / типа интерфейса, или просто иметь представление принять любой тип объекта, а затем использовать отражение, чтобы основать свое частичное поведение просмотра.
ПРИМЕР:
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
будет варьироваться в зависимости от вашего желаемого поведения. Это позволит вам затем передать что-нибудь в этот частичный объект, который реализует этот базовый интерфейс, чтобы установить общее поведение.
Я согласен с Мердадом, насколько я знаю, что невозможно сделать общие взгляды. В одном из моих проектов я использовал интерфейс, очень похожий на ваш, а затем передал функции делегирования представлению, которое обрабатывает конкретную визуализацию каждого элемента.
Например, я бы использовал класс данных неуниверсального представления с дополнительным полем:
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>
<%
}
%>
Конечно, приведенный выше код отображает только одну ячейку для каждого элемента, вам придется создать несколько более сложный делегат для отображения нескольких столбцов (или передать массив делегатов, по одному для каждого столбца).
Я думаю, что это был бы один из самых чистых способов сделать это, хотя и немного громоздким.
@ 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>
Как видите, ни один из кодов в моей части не зависит от используемого типа. Поэтому я все еще думаю, что есть простое решение.