ASP.NET MVC 2 Templates, Part 4: Custom Object Templates

Series Index

Customizing Templates

In Part 3, we saw what the default templates would look like if we’d written them as .ascx files. In this blog post, we’ll discuss some of the customizations you can make to the Object templates to enable different features and different displays for your template-based UI.

For these examples, here are the models, controller, and views that we’ll be using.

Models/SampleModel.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
 
public class SampleModel {
    public static SampleModel Create() {
        return new SampleModel {
            Boolean = true,
            EmailAddress = "admin@contoso.com",
            Decimal = 21.1234M,
            Integer = 42,
            Hidden = "Uneditable",
            HiddenAndInvisible = "Also uneditable",
            Html = "This is <b>HTML</b> enabled",
            MultilineText = "This\r\nhas\r\nmultiple\r\nlines",
            NullableBoolean = null,
            Password = "supersecret",
            String = "A simple string",
            Url = "http://www.microsoft.com/",
        };
    }
 
    public bool Boolean { get; set; }
 
    [DataType(DataType.EmailAddress)]
    public string EmailAddress { get; set; }
 
    public decimal Decimal { get; set; }
 
    [HiddenInput]
    public string Hidden { get; set; }
 
    [HiddenInput(DisplayValue = false)]
    public string HiddenAndInvisible { get; set; }
 
    [DataType(DataType.Html)]
    public string Html { get; set; }
 
    [Required]
    [Range(10, 100)]
    public int Integer { get; set; }
 
    [DataType(DataType.MultilineText)]
    public string MultilineText { get; set; }
 
    public bool? NullableBoolean { get; set; }
 
    [DataType(DataType.Password)]
    public string Password { get; set; }
 
    public string String { get; set; }
 
    [DataType(DataType.Url)]
    public string Url { get; set; }
 
    [DisplayFormat(NullDisplayText = "(null value)")]
    public ChildModel ChildModel { get; set; }
}

Models/ChildModel.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System.ComponentModel.DataAnnotations;
 
[DisplayColumn("FullName")]
public class ChildModel {
    [Required, StringLength(25)]
    public string FirstName { get; set; }
 
    [Required, StringLength(25)]
    public string LastName { get; set; }
 
    [ScaffoldColumn(false)]
    public string FullName {
        get {
            return FirstName + " " + LastName;
        }
    }
}

Controllers/HomeController.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System.Web.Mvc;
 
public class HomeController : Controller {
    static SampleModel model = SampleModel.Create();
 
    public ViewResult Index() {
        return View(model);
    }
 
    public ViewResult Edit() {
        return View(model);
    }
 
    [HttpPost]
    [ValidateInput(false)]
    public ActionResult Edit(SampleModel editedModel) {
        if (ModelState.IsValid) {
            model = editedModel;
            return RedirectToAction("Details");
        }
 
        return View(editedModel);
    }
}

Views/Home/Index.aspx

1
2
3
4
5
6
7
8
9
10
11
12
<%@ Page
    Language="C#"
    MasterPageFile="~/Views/shared/Site.master"
    Inherits="ViewPage<SampleModel>" %>
 
<asp:Content ContentPlaceHolderID="MainContent" runat="server">
    <h3>Details</h3>
    <fieldset style="padding: 1em; margin: 0; border: solid 1px #999;">
        <%= Html.DisplayForModel() %>
    </fieldset>
    <p><%= Html.ActionLink("Edit", "Edit") %></p>
</asp:Content>

Views/Home/Edit.aspx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@ Page
    Language="C#"
    MasterPageFile="~/Views/shared/Site.master"
    Inherits="ViewPage<SampleModel>" %>
 
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h3>Edit</h3>
    <% using (Html.BeginForm()) { %>
        <fieldset style="padding: 1em; margin: 0; border: solid 1px #999;">
            <%= Html.ValidationSummary("Broken stuff:") %>
            <%= Html.EditorForModel() %>
            <input type="submit" value="  Submit  " />
        </fieldset>
    <% } %>
    <p><%= Html.ActionLink("Details", "Index") %></p>
</asp:Content>

The Default Display

When we show this home controller without any customizations, this is what the details page looks like:

And this is our edit page:

Tabular Layout

One of the more commonly requested layouts is to do a tabular layout inside of the linear name/value, name/value layout that we do by default. Notice that the editor version of this layout also adds asterisks to the label for required fields.

Views/Shared/DisplayTemplates/Object.ascx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% if (Model == null) { %>
    <%= ViewData.ModelMetadata.NullDisplayText %>
<% } else if (ViewData.TemplateInfo.TemplateDepth > 1) { %>
    <%= ViewData.ModelMetadata.SimpleDisplayText %>
<% } else { %>
    <table cellpadding="0" cellspacing="0" border="0">
    <% foreach (var prop in ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm))) { %>
        <% if (prop.HideSurroundingHtml) { %>
            <%= Html.Display(prop.PropertyName) %>
        <% } else { %>
            <tr>
                <td>
                    <div class="display-label" style="text-align: right;">
                        <%= prop.GetDisplayName() %>
                    </div>
                </td>
                <td>
                    <div class="display-field">
                        <%= Html.Display(prop.PropertyName) %>
                    </div>
                </td>
            </tr>
        <% } %>
    <% } %>
    </table>
<% } %>

Which creates this layout:

Views/Shared/EditorTemplates/Object.ascx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% if (ViewData.TemplateInfo.TemplateDepth > 1) { %>
    <%= ViewData.ModelMetadata.SimpleDisplayText %>
<% } else { %>
    <table cellpadding="0" cellspacing="0" border="0">
    <% foreach (var prop in ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForEdit && !ViewData.TemplateInfo.Visited(pm))) { %>
        <% if (prop.HideSurroundingHtml) { %>
            <%= Html.Editor(prop.PropertyName) %>
        <% } else { %>
            <tr>
                <td>
                    <div class="editor-label" style="text-align: right;">
                        <%= prop.IsRequired ? "*" : "" %>
                        <%= Html.Label(prop.PropertyName) %>
                    </div>
                </td>
                <td>
                    <div class="editor-field">
                        <%= Html.Editor(prop.PropertyName) %>
                        <%= Html.ValidationMessage(prop.PropertyName, "*") %>
                    </div>
                </td>
            </tr>
        <% } %>
    <% } %>
    </table>
<% } %>

Which creates this layout:

Shallow Dive vs. Deep Dive

In the screenshots above, ChildModel is showing as “(null value)”. ChildModel is itself a complex model, so it follows the rules for shallow dive vs. deep dive. Before we have a child model object, it’s showing the NullDisplayText as we set in the attribute in the model above.

Notice that even in edit mode above, we can’t edit the child model. That’s because the shallow dive logic prevents us from presenting a recursive editing UI.

If we change the Editor template above and remove the first “if” statement (which is what prevents the deep dive), then the editor will now show us editing fields for the child model:

And now our display shows:

Since we haven’t changed our Object Display template, we still get a shallow dive on this object. Further, it’s showing us the full name because we’ve used the DataAnnotations [DisplayColumn] attribute to say “display this property when showing this complex object in shallow form”. We’ve pointed [DisplayColumn] to a synthesized property called FullName, which we don’t normally show because we’ve annotated it with [ScaffoldColumn(false)].

If we change the Object Display template to do a deep dive, then we would see this:

Wrapping Up

In this blog post, I’ve shown you some of the ways you can customize the Object template to get different displays for your templates. That includes a tabular display instead of a linear display, adding asterisks to field names when fields are required, as well as enabling Deep Dive scenarios for complex objects inside of complex objects. In the next blog post, I’ll examine changing all the templates to enable an entirely different layout system centered around Master pages, inspired by Eric Hexter’s Opinionated Input Builders blog post series.

文章引自:http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-4-custom-object-templates.html

display模版详细介绍的更多相关文章

  1. cPage分页详细介绍

    asp.net中各种数据控件,datalist.gridview.Repeater等分页是最常用的功能,几乎任何一个B/S项目,无论是系统还是网站都会用到.分页时,读取整个数据,直接绑定到控件,都可以 ...

  2. ThinkPHP框架视图详细介绍 View 视图--模板(九)

    原文:ThinkPHP框架视图详细介绍 View 视图--模板(九) 视图也是ThinkPHP使用的核心部分: 一.模板的使用 a.规则 模板文件夹下[TPL]/[分组文件夹/][模板主题文件夹/]和 ...

  3. react-native热更新之CodePush详细介绍及使用方法

    react-native热更新之CodePush详细介绍及使用方法 2018年03月04日 17:03:21 clf_programing 阅读数:7979 标签: react native热更新co ...

  4. HTML5中<template>标签的详细介绍

    HTML5中<template>标签的详细介绍(图文) 这篇文章主要介绍了HTML5中的template标签,是HTML5入门中的重要知识,需要的朋友可以参考 一.HTML5 templa ...

  5. DICOM:DICOM Print 服务详细介绍

      目录(?)[-] 背景 DICOM Print服务数据流 DICOM Print服务各部分关系 DICOM Print服务具体实现   背景: 昨天专栏中发表了一篇关于DICOM Print的博文 ...

  6. kubernetes实战篇之helm示例yaml文件文件详细介绍

    系列目录 前面完整示例里,我们主要讲解helm打包,部署,升级,回退等功能,关于这里面的文件只是简单介绍,这一节我们详细介绍一下这里面的文件,以方便我们参照创建自己的helm chart. Helm ...

  7. Android自动化测试探索(一)adb详细介绍

    adb详细介绍 #1. 基本简介 adb,即Android Debug Bridge,它是Android开发/测试人员不可替代的强大工具 #2. Mac上安装adb 安装brew /usr/bin/r ...

  8. bootloader 详细介绍

    Bootloader 对于计算机系统来说,从开机上电到操作系统启动需要一个引导过程.嵌入式Linux系统同样离不开引导程序,这个引导程序就叫作Bootloader. 6.1.1  Bootloader ...

  9. [No0000A7]批处理经常用到的变量及批处理>NUL详细介绍

    绝对路径是指调用绝对的程序位置的路径,例如: start C:\Windows\test.exe 相对路径是文件改变路径以后还会按照变量的路径所在位置去调用,例如: start %WINDIR%\te ...

随机推荐

  1. 用python做些有意思的事——分析QQ聊天记录——私人订制

    之前,写了这篇文章,用python提取全部群成员的发言时间,并简单做了下分析.先补充一下,针对特定单个群成员(这里以  小小白   为例)消息记录的获取. 代码比较简单,主要是正则表达式的书写.(附: ...

  2. HDU 5644 (费用流)

    Problem King's Pilots (HDU 5644) 题目大意 举办一次持续n天的飞行表演,第i天需要Pi个飞行员.共有m种休假计划,每个飞行员表演1次后,需要休假Si天,并提供Ti报酬来 ...

  3. JS实现Tab选项卡

    http://www.jb51.net/article/24694.htm http://www.sunsean.com/idTabs/#t1 http://www.cnblogs.com/sskse ...

  4. 转载:CancellationToken

    http://www.cnblogs.com/Abbey/archive/2011/09/12/2174208.html 最近在学习.NET中的线程同步.其中一个重要的技术叫线程的取消(中止),涉及的 ...

  5. Pike学习笔记

    Pike的安装(Ubuntu环境) pike的语法非常像C++,但是它也是脚本语言,所以具有一般脚本语言的特性.一个简单的pike程序,hello world: int main() { write( ...

  6. Day07_面向对象第二天

    1.构造方法(掌握) 1.构造方法的特点(掌握)      A.方法名必须和类名保持一致      B.没有返回值类型并且没有具体的返回值   2.构造方法的作用(掌握)       给对象的属性初始 ...

  7. win7共享wifi

    已管理员身份打开 命令提示符 netsh wlan set hostednetwork mode=allow ssid=abcde key=123456 netsh wlan start hosted ...

  8. test Windows Live Writer

    1, 下载Live Writer http://windows.microsoft.com/zh-cn/windows-live/essentials-other#essentials=overvie ...

  9. ME23N PO 打印预览 打印问题

    ME23N进入PO订单,点message查看订单打印的配置 点message查看订单打印的配置 然后spro查看 选择相应的outputtype,然后双击processing routines 可以看 ...

  10. c 函数及指针学习 7

    1.结构的存储分配 1 2 printf("%d \n",sizeof(char)); printf("%d \n",sizeof(int)); int 类型为 ...