asp.net MVC 3 Framework Learning Notes Model Templates

Source: Internet
Author: User
Tags foreach datetime

. Using a templated view Helpers (using Templated View Helpers)
Stencil View the idea of helpers is that they are more flexible. We don't have to specify what HTML elements should be used to render a model's properties, MVC will fix it, and when we update the view model, we don't have to manually update the view. Here is an example:

The code is as follows Copy Code

Add Persons.cs inside the models
Using System;
Using System.Collections.Generic;
Using System.Linq;
Using System.Web;
Using System.ComponentModel.DataAnnotations;
Using SYSTEM.WEB.MVC;

Namespace Modeltemplates.models
{
public partial class person
{

[Hiddeninput (Displayvalue = False)]
public int PersonId {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}

[DataType (Datatype.date)]
Public DateTime birthdate {get; set;}

Public address homeaddress {get; set;}

[Additionalmetadata ("Renderlist", "true")]
public bool isapproved {get; set;}

[UIHint ("Enum")]
Public role, {get; set;}
}

public class Address
{

public string Line1 {get; set;}

public string Line2 {get; set;}

public string City {get; set;}

public string PostalCode {get; set;}

public string Country {get; set;}
}

public enum role
{
Admin,
User,
Guest
}
}

Add a homecontroller as follows:


Namespace Modeltemplates.controllers


{


public class Homecontroller:controller


{


Public ActionResult Index ()


{


Person MyPerson = new person


{


PersonId = 1,


FirstName = "Joe",


LastName = "Smith",


Birthdate = DateTime.Parse ("1988-1-15"),


homeaddress = new Address


{


Line1 = "Shudu Avenue",


Line2 = "28# Dacishi Road",


City = "London",


Country = "UK",


PostalCode = "WC2R 1SS"


},


IsApproved = True,


Role = Role.user


};


Return View (MyPerson);


}

}
}

The index view is as follows
@model ModelTemplates.Models.Person
@{
Viewbag.title = "Index";
}
Person<div class= "Field" >
<label>
Name:</label>
@Html. editorfor (x => x.firstname)
@Html. editorfor (x => x.lastname)
</div>
<div class= "Field" >
<label>
Approved:</label>
@Html. editorfor (x => x.isapproved)
</div>

The editable HTML element shown above modifies the index view to read-only, as follows:

The code is as follows Copy Code
<div class= "Field" >
<label>
Name:</label>
@Html. displayfor (x => x.firstname)
@Html. displayfor (x => x.lastname)
</div>
<div class= "Field" >
<label>
Approved:</label>
@Html. displayfor (x => x.isapproved)
</div>

Run the program to see the effect. Imagine that most MVC programs have a lot of editing or displaying data, and this is a very convenient way to do it. The following is an MVC Modular HTML helper method:

The code is as follows Copy Code
Html.display ("FirstName") html.displayfor (x => x.firstname) html.editor ("FirstName") html.editorfor (x => x.firs Tname) Html.label ("FirstName") html.labelfor (x => x.firstname)
Html.displaytext ("FirstName")
Html.displaytextfor (x => x.firstname)

The above helper method is for a single model attribute, and the MVC helper method includes a method for generating HTML for the entire model object. This process is called scaffolding (scaffolding), and these methods are as follows:
Html.displayformodel () Html.editorformodel () Html.labelformodel ()
Modify the index view code as follows:

/table>
  code is as follows copy code
@model MVCApp.Models.Person
 
@{
    viewbag.title = "Index";
}
 
 
@Html. Editorformodel ()

2. Style-generated HTML (styling generated HTML)
When we use the template helper method to create the editor, the value of the class attribute inside the Html element is useful for setting the output style, such as @html.editorfor (M => m.birthdate), and the resulting HTML elements are as follows:< Input class= "Text-box single-line" id= "birthdate" name= "birthdate" type= "text" value= "1988/1/15"/>
Of course, you can also use @html.editorformodel (), which makes it easy to set the style of the generated Html by using the attribute values of these classes. The style sheet here is ~/content/site.css
3. Use model meta data (using Model Metadata)
If you need to hide or set a property to read-only, you can use the model metadata to customize our requirements by adding attributes (attributes) to the model's properties.
Controls editable and availability using elements (using Metadata to control Editing and Visibility)
In our person class, the PersonID attribute is not to be seen or edited by the user, at which point we can use the Hiddeninput feature, as follows:
[Hiddeninput (Displayvalue = False)]
public int PersonId {get; set;}
After applying this feature, we can run the program and look at the HTML source to see the following:


If we want to exclude an attribute from the generated HTML, we can use the Scaffoldcolumn attribute, such as:

The code is as follows Copy Code
public class Person {
[Scaffoldcolumn (False)]
public int PersonId {get; set;}
...
}

When the scaffolding method encounters the Scaffoldcolumn attribute, the property is skipped and the hidden INPUT element is not created. The Scaffoldcolumn attribute does not have an effect on a single property method, for example: @Html. Editorfor (M=>m.personid) generates an edit Html element for the PersonId property. Even if it uses the Scaffoldcolumn attribute.

Using the label metadata (using Metadata for Labels)
By default, the Label,labelfor,labelformodel method uses the property name as the contents of the LABEL element. For example: @Html. Labelfor (m=>m.birthdate), the page is displayed as:
<label for= "Birthdate" >BIRTHDATE</LABEL> Of course, a lot of time to directly show the property name is not what we need. If we want to specify what is displayed, you can use the display feature. as follows:
[Display (name= birthday)]
public DateTime birthdate {get; set;} The
page appears as: <label for= "birthdate" > Birthday </label>
If we set the display attribute value on the Birthdate attribute only, the date displayed on the interface is inclusive of time. If we do not want to display the time section, we can use the data value metadata. as follows:
[DataType (datatype.date)]
[Display (name= "Date of Birth")]
public DateTime birthdate {get;
Only the date part is displayed. DataType contains multiple enumeration values: Datetime,date,time,text,multilinetext,password,url,emailaddress

Use meta data to select a presentation template (using Metadata to select a display Template)
A template is based on the type of the property being processed and the helper method class used. We can use the UIHint attribute to specify the template to render to a property. As follows:
[UIHint ("Multilinetext")]
public string FirstName {get; set;}
This is the interface show FirstName is a multiline text box. There are a number of built-in view templates:
Boolean,collection,decimal,emailaddress,hiddeninput,html,multilinetext,object,password,string,text,url
Note: When using the UIHint attribute, if the template that we select cannot manipulate the type of the property, it throws an exception, such as a Boolean template for a string attribute. The object template inside is also a special case, it is scaffolding auxiliary method (Html.displayformodel (), Html.editorformodel (), Html.labelformodel ()) Used to generate HTML for the view model object. This template examines all the properties of an object and selects a template that best fits the property type.

Use meta data for partner classes (applying Metadata to a Buddy class)
Metadata is not always used for the entire model class, which is often useful for automatically generated model classes, such as when using ORM tools. Any changes to the automatically generated model class will be overwritten the next time it is built. The solution to this problem is to create the model class as partial and create the first partial class to apply the metadata. The person class is modified to partial below:

  code is as follows copy code
public partial Class Person
{
    public int PersonId {get; set;}
    public string FirstName {get; set;}     
    public string LastName {get; set;}
    Public DateTime birthdate {get; set;}
    Public address homeaddress {get; set;}
    public bool isapproved {get; set;}
    Public role role {get; set;}
}

A partial class must have the same name and be declared in the same namespace, with the partial keyword, of course. In addition to the purpose of metadata, a key feature is Metadatatype, which enables us to associate the partner class with the person class by passing the type of the partner class as a parameter to the person. Such as:

The code is as follows Copy Code
[Metadatatype (typeof (Personmetadatasource))]
public partial class Person {

}
Class Personmetadatasource {

[Hiddeninput (Displayvalue=false)]
public int PersonId {get; set;}

[DataType (Datatype.date)]
Public DateTime birthdate {get; set;}
}

The partner class just needs to contain the attributes we want to apply metadata without having to replicate the attributes of all the person classes. In the example above, the datatype attribute is used to ensure that the Birthdate property is displayed correctly.

Apply Complex type parameters (Working with Complex type Parameters)
The template process relies on the object template, and each property is instrumented, but only one template is used to render the HTML element that represents the attribute and its value. We also note that when using the scaffolding method (Editorformodel,displayformodel), not all attributes need to be rendered. In fact, the homeaddress attribute is ignored because the object template simply operates on a simple type-that is, a static method that can be used System.ComponentModel.TypeDescriptor getconverter Types converted from string, containing C # Basic types: Int,bool and Doubl, also included. NET Framework, the type GUID and datetime are commonly used. The result of this strategy is that scaffolding is not recursive or cyclical, given an object processing, the Scaffolding Template View helper method only generates properties of simple types and ignores complex objects. Although this may not be convenient, it is a very sensible strategy. The MVC framework does not know how our model objects were created, and if the object template is recursive, we can easily terminate the ORM delay-loading feature, allowing us to read and render objects for each database. If we want to render HTML for a complex property, we need to display the specified, as follows:

The code is as follows Copy Code
<div class= "column" > @Html. Editorformodel () </div>
<div class= "column" >
@Html. Editorfor (M => m.homeaddress)
</div>

When we use the Editorfor method, the object template is called to be displayed, so that all the metadata conventions are respected.

Customizing the Graphical View Helper system (customizing the Templated View Helper Systems)
It shows how metadata can be used to shape the way the template helper renders data, and provides some advanced options for customizing the entire template helper in MVC. The following is an introduction:
Create a custom edit template (creating a custom Editor Template)
One of the simplest customization templates helper is to create a custom template that we render HTML directly. As an example, we create a custom template for the role attribute of the person class, with the view code as follows:

The code is as follows Copy Code
@model MVCApp.Models.Person
<p>
@Html. Labelfor (M => m.role):
@Html. Editorfor (M => m.role)
</p>
<p>
@Html. Labelfor (M => m.role):
@Html. Displayfor (M => m.role)
</p>

This view is very simple, the label and display templates are very useful, but the editor way of showing role is not what we like, because the role of the enumeration value of three, here is a random rendering of a value, and our expectations are too far away, You can use the Html.dropdownlistfor method here, but it's still not perfect, because we copy it manually every time we need role editor. Here you can create a template view, which essentially creates a partial view where you actually need it. First create a EditorTemplates folder in shared, and then add a partial view such as:

The code is as follows Copy Code
@using Modeltemplates.models
@model role
<select id= "role" name= "role" >
@foreach (role value in Enum.getvalues (typeof))
{
<option value= "@value" @ (Model = = value?) "Selected=" Selected "": "" > @value </option>
}
</select>

This view creates an HTML select element and populates each of the role's enumerated values as a selection. When we render a editor element for this property, some views are used to generate HTML. The code that can modify the index view is: @Html. Editorformodel (), and running the program will see the effect. Here we might be surprised that we didn't introduce that part of the view in the index view, but we were able to display the HTML element of role. Because we have defined a role.cshtml template in shared, the enumeration name is also role, so this should be a convention to find. But in fact, we can modify it to role1.cshtml, and running the program can still get the desired result. This is based on the type of role in the template that matches the lookup, and the template can be used for any type of attribute that is role. Here is an example:
Create a Simplemodel:

The code is as follows Copy Code

public class Simplemodel {
public string Name {get; set;}
Public role Status {get; set;}
}

The code for the Simplemodel view is as follows:
@model ModelTemplates.Models.SimpleModel
@{
Viewbag.title = "Simplemodel";
}
Simplemodel@Html. Editorformodel ()

Enter/home/simplemodel to see the effect.

Understand template search order (understanding the TEMPLATE)
The reason our custom role.cshtml can run is because the MVC framework looks for a custom template for a given C # type before using the built-in template. Here is the order to find:
1. If it is html.editorfor (M => m.someproperty, "MyTemplate"), the MyTemplate template will be used.
2. Any template that has been assigned metadata, such as UIHint
3. Templates associated with data types that specify metadata, such as datatype attributes
4. Any data type that is processed. NET class name in a consistent template
5. If the data type being processed is a simple type, the built-in string template is used
6. Any template consistent with the base class of the data type
7. If the data type implements IEnumerable, then the built-in collection template will be used
8. If the above match fails, then the object template will be used
Some of these steps rely on built-in templates, such as the above example, to look for an MVC framework called editortemplates/<name> or displaytemplates/<name>. For our role template, this matches the fourth step above. The found view uses the same search pattern as the usual view, which means that we can create a custom template for the specified controller and place it under the ~/views/<controller>/editortemplates folder, overriding the ~/views/ Templates found under shared files.

Create a custom presentation template (creating a custom display Template)
The process here is similar to the above, creating the DisplayTemplates folder under shared and adding role.cshtml as follows:

The code is as follows Copy Code
@model role

@foreach (role value in Enum.getvalues (typeof))
{
if (value = = Model) {
<b> @value </b>
} else {
@value
}
}

Run the program to see the effect, where you need to note that the two folder names created under shared are well appointed and cannot be changed to another.

Create a generic template (creating a Generic Template)
We can also create an enumeration for all and use the UIHint attribute to specify which template is selected. If we look at the search order for the template above, we can see that the template that specifies the UIHint feature takes precedence over the specified type. The following is a enum.cshtml template, which can be more versatile in the treatment of C # enumerations. As shown below:

The code is as follows Copy Code
@model Enum
@Html. Dropdownlistfor (M => m, Enum.getvalues (Model.gettype ())
   . Cast<enum> ()
   . Select (M =>
    {
        string enumval = Enum.getname ( Model.gettype (), m);
        return new SelectListItem ()
         {
            Selected = (model.tostring () = = Enumval),
            Text = enumval,
             Value = Enumval
        };
   }))

The above template allows us to handle any enumeration, in the example above, we used the strongly typed Dropdownlistfor helper method and used some LINQ logic to convert the enumeration value to SelectListItem. The following applies the UIHint template to the role attribute:
[UIHint ("Enum")]
Public role, {get; set;}

Replace the built-in template (replacing the built-in Templates)
If we create a template with the same name as a built-in template, the MVC framework uses a custom version. The following shows the substitution of the Boolean template to render bool and bool. Values, as follows:

The code is as follows Copy Code
@model bool?
@if (ViewData.ModelMetadata.IsNullableValueType && Model = null)
{
@:true False <b>not set</b>
}
else if (model.value)
{
@:<b>true</b> False not Set
}
Else
{
@:true <b>False</b> not Set
}

Note: Search replaces the built-in template's custom template order following the standard template pattern, we can put the view under the ~/views/shared/displaytemplates folder, which means that the MVC framework can use this template in any situation that requires a Boolean. We can also use the ~/views/<controller>/displaytempates qualifier template for a single controller only.

Use the Viewdata.templateinfo attribute (using the Viewdata.templateinfo property)
The MVC Framework provides Viewdata.templateinfo properties to make custom templates easier, and this property returns a Templateinfo object, which lists some of the most useful members of this class:
Formattedmodelvalue: Returns a string of the current model and formats the metadata like the datatype attribute.
Getfullhtmlfieldid (): Returns a string that can be used for HTML ID attributes
Getfullhmlfieldname (): Returns a string that can be used for the HTML Name property
Htmlfieldprefix: Returns the prefix of a field

About data Format (respecting) formatting
Perhaps the most useful templateinfo attribute is Formattedmodelvalue, which allows us to observe and format metadata without having to examine and process these features ourselves. The following is a datetime.cshtml custom template that is used to generate editor elements for a DateTime object.


@model DateTime
@{
var ti = viewdata.templateinfo;
<input id= "@ti. Getfullhtmlfieldid (ti. Htmlfieldprefix) "Name=" @ti. Getfullhtmlfieldname (ti. Htmlfieldprefix) "type=" text "value=" @ti. Formattedmodelvalue "/>
}
Run the program, you can view the next page source code, as follows:

Using the HTML prefix (Working with HTML prefixes)
When we present a hierarchical view, the MVC framework tracks the property names we render and provides us with a unique reference point through the Htmlfieldprefix attribute. This is especially useful when we're dealing with nested objects, such as the HomeAddress property here, for example: @Html. editorfor (M => m.homeaddress.postalcode), The value of the Htmlfieldprefix passed to the template is Homeaddress.postalcode. Under Shared/editortemplates, create a postalcode.cshtml template as follows:

The code is as follows Copy Code
@model string
@{var ti = viewdata.templateinfo;
<input id= "@ti. Getfullhtmlfieldid (ti. Htmlfieldprefix) "Name=" @ti. Getfullhtmlfieldname (ti. Htmlfieldprefix) "type=" text "
Value= "@ti. Formattedmodelvalue "/>
}

Then run the program to view the page source:
Of course, can also be written directly in the template: @ViewData. templateinfo.htmlfieldprefix
Using this approach guarantees the unique identification of the HTML elements we create-usually the ID and the name attribute. The value returned by the Htmlfieldprefix property is usually not used directly as a property, so the Templateinfo object contains the Getfullhtmlfieldid and Getfullhtmlfieldname methods to convert to something that can be used. The value of the HTML prefix will be very clear in the next chapter.

Pass additional meta data to the template (passing Additional Metadata to a Template)
If we want to provide an additional guideline to the template, this cannot be achieved with the built-in attributes. You can then use the Additionalmetadata property as follows:
[Additionalmetadata ("Renderlist", "true")]
public bool isapproved {get; set;}
We use Additionalmetadata for the isapproved attribute, which requires a key-value pair to be used as a parameter. In this example we use a renderlist as a key to specify whether the attribute of type bool should use DropDownList (true) or TextBox (false) to detect these values through the ViewData property template. Modify Boolean.cshtml as follows:

The code is as follows Copy Code

@model bool?
@{
bool Renderlist = true;
if (ViewData.ModelMetadata.AdditionalValues.ContainsKey ("Renderlist"))
{
Renderlist =
bool. Parse (viewdata.modelmetadata.additionalvalues["Renderlist"). ToString ());
}
}
@if (Renderlist)
{

SelectList list = ViewData.ModelMetadata.IsNullableValueType?
New SelectList (new[] {"True", "False", "Not Set"}, Model):
New SelectList (new[] {"True", "False"}, Model);

@Html. Dropdownlistfor (M => m, list)

}
Else
{
@Html. Textboxfor (M => m)
}

Understanding the metadata delivery system (understanding the Metadata Provider System)
So far, examples of metadata presented are dependent on the Dataannotationsmodelmetadataprovider class, which detects and processes the attributes added to it so that templates and formatting options can be used.
The base of the model metadata system is the Modelmetadata class, which contains many attributes (specifying how a model or attribute should be rendered). Dataannotationsmodelmetadata handles the attributes that we apply and set values for the properties of Modelmetadata objects (Attributes), which are then passed to the template system for processing. To see the most commonly used properties of the Modelmetadata class, Bash here
Create a custom model metadata provider (creating a custom model Metadata Provider)
The provider you created must derive from Modelmetadataprovider, as follows:

The code is as follows Copy Code
Namespace SYSTEM.WEB.MVC


{


Using System.Collections.Generic;





Public abstract class Modelmetadataprovider


{





Public abstract ienumerable&lt;modelmetadata&gt; Getmetadataforproperties (


Object container, Type containertype);





Public abstract Modelmetadata Getmetadataforproperty (


Func&lt;object&gt; Modelaccessor, Type containertype, String PropertyName);





Public abstract Modelmetadata Getmetadatafortype (


Func&lt;object&gt; modelaccessor, Type modeltype);


}


}


We can implement each of these methods in the custom, a simple way is to derive a class from the Associatedmetadataprovider class, so that we only need to implement a single method, the following shows an implementation of the provider:

The code is as follows Copy Code

Create under Modeltemplates/infrastructure
Using SYSTEM.WEB.MVC;

Namespace Modeltemplates.infrastructure
{
public class Custommodelmetadataprovider:associatedmetadataprovider
{

protected override Modelmetadata Createmetadata (ienumerable&lt;attribute&gt; attributes, Type containertype, func&lt; Object&gt; Modelaccessor, Type modeltype, String propertyname)


{


Modelmetadata metaData = new Modelmetadata (this, Containertype, Modelaccessor, Modeltype, PropertyName);


if (propertyname!= null &amp;&amp; propertyname.endswith ("Name"))


{


Metadata.displayname = propertyname.substring (0, propertyname.length-4);


}


return metaData;


}


}


}


Specify our custom provider in Global.asax


protected void Application_Start ()


{


Arearegistration.registerallareas ();


Modelmetadataproviders.current = new Custommodelmetadataprovider ();


Registerglobalfilters (globalfilters.filters);


RegisterRoutes (routetable.routes);


}

Custom data identification model metadata provider (customizing-annotations-mode Metadata Provider)
With a custom model metadata provider, you can't use data annotations metadata, and if you want to implement a custom policy and want to gain the benefits of data annotations, You can derive the custom model metadata provider from Dataannotationsmodelmetadataprovider, which is derived from the Associatedmetadataprovider, So we just need to rewrite the Createmetadata method as follows:

The code is as follows Copy Code

Namespace Modeltemplates.infrastructure
{
public class Custommodelmetadataprovider:dataannotationsmodelmetadataprovider
{

protected override Modelmetadata Createmetadata (ienumerable&lt;attribute&gt; attributes, Type containertype, func&lt; Object&gt; Modelaccessor, Type modeltype, String propertyname)


{


Modelmetadata MetaData = base. Createmetadata (attributes, Containertype, Modelaccessor, Modeltype, PropertyName);


if (propertyname!= null &amp;&amp; propertyname.endswith ("Name"))


{


Metadata.displayname = propertyname.substring (0, propertyname.length-4);


}


return metaData;


}


}


}

The effect of running the program here is not the same as the custom model metadata, so let us add the attributes in the model before the effective

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.