目标
我需要一个列表视图,该列表视图可以显示我抛出的任何查询,而无需创建自定义视图模型或自定义视图。
解决方案
使用反射,我可以将匿名类型传递给自定义帮助器函数,以创建表中的所有标题和行。
问题
为了获取匿名类型,我需要使用GetGenericArguments()
方法并使用[]
运算符来提取该信息。但是,当我使用命名的Type
(我已经硬编码的模型)时,从IEnumerable<object>
行中获取该类型的必要索引为0。当我使用匿名类型时,必要的索引索引是1。为什么会这样?还有什么更好的方法可以使我获得Type
?
代码
控制器:
(我可以将这些模型查询中的任何一个传递给视图,并相应地显示表格)
public ActionResult Index()
{
var models = taskService.ReadMany().Select(m => new
{
Name = m.Title,
Summary = m.Details,
Importance = m.Priority,
DueDate = m.DateDue
});
var models = taskService.ReadMany();
var models = taskService.ReadMany().GroupBy(m => new { m.DateDue }).Select(m => new { NumberOfProjects = m.Count(), DueOn = m.Key.DateDue });
return View(models);
}
助手扩展:
public static MvcHtmlString BuildHeaders(this HtmlHelper html, Type type)
{
var tr = new TagBuilder("tr");
var model = type;
foreach (MemberInfo prop in model.GetProperties())
{
var th = new TagBuilder("th");
var display = prop.GetCustomAttribute(typeof(DisplayAttribute)) as DisplayAttribute;
if (display != null) th.InnerHtml = display.Name;
else if (!prop.Name.Contains("Id")) th.InnerHtml = prop.Name;
else continue;
tr.InnerHtml += th.ToString();
}
return MvcHtmlString.Create(tr.ToString());
}
public static MvcHtmlString BuildRow(this HtmlHelper html, object model)
{
var tr = new TagBuilder("tr");
var type = model.GetType();
foreach (PropertyInfo prop in type.GetProperties())
{
var td = new TagBuilder("td");
var val = prop.GetValue(model, null);
string valString = "";
if (val != null) valString = val.ToString();
if (!prop.Name.Contains("Id")) td.InnerHtml = valString;
else continue;
tr.InnerHtml += td.ToString();
}
return MvcHtmlString.Create(tr.ToString());
}
列表视图:
@model IEnumerable<object>
@{
ViewBag.Title = "Index";
Type type = Model.GetType().GetGenericArguments()[1]; //this line if I'm using an anonymous type
Type type = Model.GetType().GetGenericArguments()[0]; //this line if I'm using a named type. I need to make this line handle both situations without manual intervention
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
@Html.BuildHeaders(type)
@foreach (object item in Model) {
@Html.BuildRow(item)
}
</table>