在ASP.NET MVC自动脚手架模板上苦苦挣扎

时间:2010-03-14 20:45:54

标签: c# html asp.net-mvc templates

我正在尝试为Index视图编写一个自动脚手架模板。我希望能够传递一组模型或视图模型(例如IQueryable<MyViewModel>)并获取一个HTML表格,该表格使用DisplayName属性作为标题({{1}元素)和th用于单元格(Html.Display(propertyName)元素)。每行应对应于集合中的一个项目。

这是我到目前为止所拥有的:


td

有两个问题:

  1. 我希望它是通用的。因此,我想将<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> <% var items = (IQueryable<TestProj.ViewModels.TestViewModel>)Model; // How do I make this generic? var properties = items.First().GetMetadata().Properties .Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm)); %> <table> <tr> <% foreach(var property in properties) { %> <th> <%= property.DisplayName %> </th> <% } %> </tr> <% foreach(var item in items) { HtmlHelper itemHtml = ????; // What should I put in place of "????"? %> <tr> <% foreach(var property in properties) { %> <td> <%= itemHtml.Display(property.DisplayName) %> </td> <% } %> </tr> <% } %> </table> 替换为var items = (IQueryable<TestProj.ViewModels.TestViewModel>)Model;或其他类似内容。

  2. 创建视图时会自动为我创建属性var items = (IQueryable<T>)Model;,但此Html适用于整个集合。我需要以某种方式创建一个HtmlHelper对象,该对象仅适用于itemHtml循环中的当前项。但是,我不知道如何执行此操作,因为foreach的构造函数不会使用HtmlHelper对象。

  3. 如何解决这两个问题?

4 个答案:

答案 0 :(得分:3)

答案 1 :(得分:0)

对于geniric IQueryable部分,为什么不简单地将它转换为IQueryable ......

var items = (IQueryable<TestProj.ViewModels.TestViewModel>)Model;

和你的模板是什么,它与添加视图时的默认列表模板几乎不一样...如果你想自定义它,我想你最好找一下List.tt模板。您可以修改它以使用Html.Display而不是Html.Encode。

或者您可以尝试使用

Html.DisplayFor(o => property.GetValue(item))

我不确定这是否有用......

答案 2 :(得分:0)

可悲的是你不能这样做:

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

甚至

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

ASP.NET MVC实现了一个Html.DisplayForModel(),因为Brad Wilson显示on his blog,它为您提供了开箱即用的脚手架。 (我相信你知道的,提到完整性)。

如果您查看MVC 2 RTM Source Code源代码,特别是DefaultDisplayTemplates.cs,它们基本上都包含在HTMLHelper中,就像视图一样。也许不是与视图的自动生成类进行斗争(尽管我喜欢asp.net mvc,默认视图渲染引擎是一个彻头彻尾的痛苦),而是按照ASP.NET MVC RTM实现脚手架的方式建模的HTMLHelper扩展。我想这会为代码重用提供更多的可能性(尽管几乎所有内容都是内部的)。

如果您不是默认<div class=\"display-field\">等的粉丝,那么如果ASP.NET MVC脚手架允许传入自定义模板以更改html,那将是很好的。对我来说,这是ASP.net MVC的弱点之一('硬编码'错误处理/脚手架HTML)。

如果您不是构建HTML的字符串粉丝,那么当您的脚手架HTMLHelper扩展程序收集了足够的信息以充分键入粒度视图时,您的扩展程序可以调出更细粒度的部分视图(例如ScaffoldCaption.ascx)。

答案 3 :(得分:-1)

你有没有看过MVCContrib Grid?当然有人编写了一个扩展方法来默认显示所有属性。如果不是,那应该不难。

edit2-我想在周日不相信我的答案。我之前误解了这个问题并且没有意识到Html.Display()是MVC2模板化输入。 (我在我的店里做了一些根本不同的输入构建器,所以我没有拿起名字。我只是觉得Display显示了价值。)无论如何,我在这里看到两个选项。

1)拉出MVC2源或分解Reflector并编写自己的方法,而不是扩展HtmlHelper。

2)你可以在这里使用反射来构建一个新的HtmlHelper实例,但它并不漂亮。 (我没有测试过,但应该可以使用。)

var modelType = Html.GetType().GetGenericParameters()[0];
var itemHtmlType = typeof(HtmlHelper<>).MakeGenericType(modelType);
var itemHtmlCtor = itemHtmlType.GetConstructor(typeof(ViewContext), typeof(IViewDatacontainer), typeof(RouteCollection));
var itemHtml = itemHtmlCtor.Invoke(Html.ViewContext, Html.ViewDataContainer, Html.RouteCollection);

你会得到一个对象,所以你必须使用反射来调用itemHtml.Dipslay。我建议走另一条路。