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. UNIX,基础知识,文件IO,文件和目录

    2015.1.27星期二,早晨阴天,中午下雪了今天上午老师不上课,程序语句,记一下:main(void){ int c; while((c = getc(stdin)) != EOF) if(putc ...

  2. VIM_插件

    VIM进阶:插件     通过一段时间的练习,你就可以非常熟练的使用VIM.即使是"裸奔",VIM已经足够强大,能够完成日常的绝大部分工作.     但VIM更加强大的是它的扩展机 ...

  3. 建置 POSTFIX 服务器

    建置 POSTFIX 服务器 postfix 是除了 sendmail 以外 ,最被广泛采用的 Linux 邮件服务器,一般使用的观感不外乎两点: 一.安全:垃圾信过滤机制较聪明,就算什么都没设定,也 ...

  4. POJ2449 (k短路)

    #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> # ...

  5. Unity3D ShaderLab 立方体图的菲涅尔反射

    Unity3D ShaderLab 立方体图的菲涅尔反射 菲涅尔反射是反射类型中比较常见的一种类型,当我们的视线正对物体表面,那么反射量会明显增加, 我们几乎可以在任何支持反射类型的物体表面看到这种情 ...

  6. Android FM模块学习之一 FM启动流程

    最近在学习FM模块,FM是一个值得学习的模块,可以从上层看到底层. 上层就是FM的按扭操作和界面显示,从而调用到FM底层驱动来实现广播收听的功能. FM启动流程:如下图: 先进入FMRadio.jav ...

  7. invoke Javascript from C# code

    http://justyouraveragegeek.com/blog/index.php/2010/03/winforms-with-a-webbrowsercontrol-fun-with-obj ...

  8. C++的虚函数表

    这里的例子全部来自陈皓的C++ 虚函数表解析,经过修改的. 编译器:g++ (Ubuntu 4.9.2-10ubuntu13) 4.9.2 环境:ubuntu 15.04  64位系统(地址占8字节) ...

  9. Tomcat中负载的Session解决办法

    Tomcat进行请求的Session解决方式总体来说有三种, (1)使用Nginx或者Apache反向代理工具进行用户请求的分机器,在Tomcat的Engine中的标签中加入jvmRoute属性,指定 ...

  10. sticky bit

    • Sticky Bit这个Sticky Bit当前只针对目录有效,对文件没有效果.SBit对目录的作用是:“在具有SBit的目录下,用户若在该目录下具有w及x权限,则当用户在该目录下建立文件或目录时 ...