开发者

Struggling with ASP.NET MVC auto-scaffolder template

I'm trying to write an auto-scaffolder template for Index views. I'd like to be able to pass in a collection of models or view-models (e.g., IQueryable<MyViewModel>) and get back an HTML table that uses the DisplayName attribute for the headings (th elements) and Html.Display(propertyName) for the cells (td elements). Each row should correspond to one item in the collection.

Here's what I have so far:


<%@ 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>

Two problems with this:

  1. I'd like it to be generic. So, I'd like to replace var items = (IQueryable<TestProj.ViewModels.TestViewModel>)Model; with var items = (IQueryable<T>)Model; or something to that effect.

  2. A property Html is automatically created for me when the view is created, but this HtmlHelper applies to the whole collection. I need to somehow create an itemHtml object that applies just to the current item in the foreach loop. I'm not sure how to do this, however, because the constructors for HtmlHelper don't开发者_开发百科 take a Model object.

How do I solve these two problems?


Phil Haack to the rescue!

http://haacked.com/archive/2010/05/05/asp-net-mvc-tabular-display-template.aspx


for the geniric IQueryable part, why don't you simply cast it to an IQueryable...

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

and What is your template for, isn't it almost the same as the default list template when you add a view... If you want to customize it, i think you'd better look for the List.tt template. You could modify that to use Html.Display instead of Html.Encode.

Or you could try using

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

I'm not sure if this would work...


Sadly you can't do:

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

or even

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

ASP.NET MVC implements a Html.DisplayForModel() as Brad Wilson shows on his blog which does scaffolding for you out of the box. (which I'm sure you know about, mentioning for completeness).

If you look at the MVC 2 RTM Source Code source code and in particular the DefaultDisplayTemplates.cs it's all basically contained in an HTMLHelper as suppose to a View. Perhaps instead of fighting with the auto generated class for the view (as much as I love asp.net mvc the default view rendering engine is a total pain) go with an HTMLHelper extension modelled after how ASP.NET MVC RTM implements scaffolding. I guess this would open the possibility for code reuse some more too (though almost everything is internal).

It would be nice if the ASP.NET MVC scaffolding would allow for a custom template to be passed in to change the html if you're not a fan of the default <div class=\"display-field\"> etcetera. To me this is one of the weak spots of ASP.net MVC (the 'hardcoded' error handling/ scaffolding HTML).

If your not a fan of string building your HTML, your extension could call out to more granular partial views (like ScaffoldCaption.ascx) when your scaffolding HTMLHelper extension has gathered enough information to sufficiently type the granular view.


Have you looked into the MVCContrib Grid? Certainly someone has written an extension method to show all properties by default. If not it shouldn't be difficult.

edit2- I guess don't trust my answers on Sunday. I misread the question before and didn't realize Html.Display() was the MVC2 templated input. (I'm doing some radically different input builders at my shop so I didn't pick up on the name. I just thought Display showed the value.) Anyway, there are two options I see here.

1) Pull the MVC2 source or break out Reflector and write your own method that is not extending HtmlHelper.

2) You can use reflection here to build a new HtmlHelper instance but it's not pretty. (I didn't test this but is should work.)

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);

You'll get an object out of this though so you have to use reflection to invoke itemHtml.Dipslay. I'd recommend going a different route.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜