MVC extension html.imagefor

Source: Internet
Author: User

A detailed background of the ASP. NET MVC extension Html.imagefor method:

When defining a model in ASP. NET MVC, DataType has datatype.imageurl this type, but HtmlHelper can not output an IMG, when using scaffolding to automatically generate some form or form, these URL fields always need to be changed manually, especially I want to wrap an an a tag on IMG. and limit the size, such as:

<a href= "url" target= "_blank" > </a>

Method 1: Partial view

In the background table often to modify such problems, so the first thought is to do a partial view, called Tableimg.

@model string@if (!string. IsNullOrEmpty (Model)) {<a href= "@Model" target= "_blank" > </a>}

When used:

@Html. Partial ("Tableimg", model.img)

Convenience is convenient, but still not flexible enough. The width is written dead, but also remember this view, if such fragments are too much to know who is who, and scaffolding generated code TEXTBOXFOR,DISPLAYFOR and other styles are not the same; If you want to add parameters, you have to change the model.

Method 2:uihint

This method is similar to a partial view, and also uses a template, which requires creating a EditorTemplates folder under the shared folder, and then creates a new view. This is named ImageLink. The content is the same as above.

@model string@if (!string. IsNullOrEmpty (Model)) {<a href= "@Model" target= "_blank" > </a>}

Just call the method differently:

   [DataType (Datatype.imageurl)]   [UIHint ("ImageLink")]public string Img {get; set;}

Inside the view is called through Editorfor:

This is a lot of changes, not feeling very comfortable. Can it be once and for all? Of course, it is possible to customize a modelmetadataprovider to tell MVC that the properties of this data type are displayed with this template.

public class Imagemodelmetadataprovider:dataannotationsmodelmetadataprovider    {        protected override Modelmetadata createmetadata (ienumerable<attribute> attributes, Type containertype, func<object> Modelaccessor, Type modeltype,            string propertyname)        {            var meta= base. Createmetadata (attributes, Containertype, Modelaccessor, Modeltype, PropertyName);            if (meta. Datatypename==datatype.imageurl.tostring () && string. IsNullOrEmpty (meta. Templatehint))            {                meta. Templatehint = "ImageLink";            }            return meta;        }    }

Modelmetadata is used to describe the data structure of a model, such as data types, constraints, display names, and so on, and Modelmetadataprovider is used to provide model metadata.

Then register globally:

protected void Application_Start ()        {            arearegistration.registerallareas ();            Webapiconfig.register (globalconfiguration.configuration);            Filterconfig.registerglobalfilters (globalfilters.filters);            Routeconfig.registerroutes (routetable.routes);            Bundleconfig.registerbundles (bundletable.bundles);            Modelmetadataproviders.current = new Imagemodelmetadataprovider ();        }

The definition of the model, there is no need to add uihint.

   [DataType (Datatype.imageurl)]   public string Img {get; set;}

When calling inside a view, you need to use editorfor. Looking back, this approach is still not flexible enough, to achieve an effect, the first to add a template, and then register the model metadata provider, and then every model to show the effect of the plan to force the use of datatype features and html.editorfor output, which makes a bit of a sense of bondage.

Could you just change one place? So think of the extended HtmlHelper

Method 3:html.image

Create a new static class, Htmlhelpers, add an image extension method, with URL and length two parameters. Create tags with tagbuilder and add attributes.

   public static mvchtmlstring Image (This htmlhelper helper, string url, int length)        {            var Taga = new Tagbuilder ("a") ;            Taga.mergeattribute ("href", url);            Taga.mergeattribute ("Target", "_blank");            var img = new Tagbuilder ("img");            Img. Mergeattribute ("src", url);            Img. Mergeattribute ("style", string. Format ("width:{0}px", length));            taga.innerhtml = img. ToString ();            Return Mvchtmlstring.create (Taga.tostring ());        }

Finally returned to mvchtmlstring, but the above does not reflect the benefits of Tagbuilder. If you find it troublesome to write tag, you can:

  var str= string. Format ("<a href= ' {0} ' target= ' _blank ' > </a> ", url, length);   return mvchtmlstring.create (str);

Pass in parameters when calling:

The results show OK:

But if you want to add more width and more styles, and you want to specify the ID of the IMG as the name of the model property, you have to use Imagefor.

Method 4:html.imagefor

Start will not write, think of the MVC source code, so with a strong ilspy (directly drag System.Web.MVC.dll in) Find the source code in the System.Web.MVC.HTML, directly can see Labelextension and displayextension, etc., commonly used textboxfor located in Inputextension.

So here I draw on the above method, first produce an IMG, in a expression wrapped. If you still use string here. Format that's too bad.

  Internal static mvchtmlstring Imagehelper (htmlhelper html, modelmetadata metadata, idictionary<string, object> Htmlattributes = null)        {            //property value            var value = metadata. Model.tostring ();            The property name            if (string. IsNullOrEmpty (value))            {                return mvchtmlstring.empty;            }            var img = new Tagbuilder ("img");            Img. Attributes.Add ("src", value);            Img. Attributes.Add ("id", metadata. PropertyName);
            Img. Mergeattributes (Htmlattributes, true);
var Taga = new Tagbuilder ("a");            Taga.mergeattribute ("href", value);            Taga.mergeattribute ("Target", "_blank"); taga.innerhtml = img.            ToString ();        Return Mvchtmlstring.create (Taga.tostring ()); } public static mvchtmlstring Imagefor<tmodel, tproperty> (this htmlhelper<tmodel> HTML, expression<f Unc<tmodel, tproperty>> expression, object htmlattributes) {Modelmetadata Modelmetadata = Mode Lmetadata.fromlambdaexpression (expression, HTML.            ViewData); var propertyname = expressionhelper.getexpressiontext (expression);            can also get to the attribute name var htmlAttributes2 = htmlhelper.anonymousobjecttohtmlattributes (htmlattributes);        return Imagehelper (HTML, Modelmetadata, htmlAttributes2); } public static mvchtmlstring Imagefor<tmodel, tproperty> (this htmlhelper<tmodel> HTML, Expr Ession<func<tmodel, tproperty>> expression) {REturn imagefor (HTML, expression, NULL); }

The Imagehelper method is used to produce the labels you want. Contains three parameters, HtmlHelper, Modelmetadata, Htmlattributes. HtmlHelper doesn't have to say much, it's used to generate various elements on the page, but it's not used here. Modelmetadata is the model metadata, which describes the data structure of models and some of the characteristics of each data member of model. It is with the existence of the model metadata that the templating HTML rendering mechanism becomes possible. This is used primarily to get the value of the model, which is the corresponding URL value. With a breakpoint we can see what it contains to write:

For more details, you can take a Artech blog: ASP. NET MVC model metadata and its customization: initial knowledge of the model metadata. Htmlattributes is at a glance. is a style dictionary. But when we write, we're all passing in an object, such as:

The new{wdith= ' 100px ' behind this is essentially an anonymous object, and the biggest benefit of an anonymous object is that the property can be customized, what style to add, and then converted to idictionary<string by the HtmlHelper method, Object> htmlattributes Structure

var htmlAttributes2 = htmlhelper.anonymousobjecttohtmlattributes (htmlattributes);

Look at how this source code is implemented.

A property interpreter that gets all the properties of an anonymous object through the type interpreter. and add them to the collection. This way the Tagbuilder Mergeattribute method is good for dealing with these styles or property key values.

While the model metadata is processed by the lambda expression and gets:

Modelmetadata Modelmetadata = modelmetadata.fromlambdaexpression (expression, HTML. ViewData);

The interior is implemented by Modelmetadataprovider, and Modelmetadataprovider is an abstract class that provides three abstract methods:

Public abstract class modelmetadataprovider{  protected Modelmetadataprovider ();  Public abstract ienumerable<modelmetadata> getmetadataforproperties (Object container, Type containertype);  Public abstract Modelmetadata Getmetadataforproperty (func<object> modelaccessor, Type containertype, string PropertyName);  Public abstract Modelmetadata Getmetadatafortype (func<object> modelaccessor, Type modeltype);}

Associatedmetadataprovider Inherit Modelmetadataprovider, The dataannotationsmodelmetadataprovider used above is inherited Associatedmetadataprovider. Here Artech speak more, the details please: ASP. NET MVC's model metadata provides a mechanism to implement more in-depth knowledge for the moment. This time our Imagefor method is ready to use.

@Html. Imagefor (n=>model.img) <br/> @Html. Imagefor (n=>model.img,new{width = "100px"}) <br/>

Generated HTML:

<a href= "http://photocdn.sohu.com/20160629/Img456995877.jpeg" target= "_blank" ></a><a href=" http://photocdn.sohu.com/20160629/ Img456995877.jpeg "target=" _blank "></a>

It's much more comfortable. From this we can also extend the other for method.

Html.enumtodropdownlist

With this idea, the problem of enumerating types can also be solved, you know, to enumerate the type of display characteristics of the same dummy. We generally want the enumeration type to be able to display Chinese, and the value is the enumeration on the line. For example, there are enumerations:

Public enum Questiontype    {        [Display (Name = "Radio")] single        ,

[Display (Name = "multi-select")] multiple, [Display (name = "judgment")] Jude, [Display (name = "Fill in the blanks")] Blank, [Display (name = "question and answer")] Question }

If the view is written like this:

@Html. dropdownlistfor (n = n.questiontype, new SelectList (Enum.getvalues (typeof (Questiontype))))

You can only get the English drop-down box:

Online also useful methods to solve enumeration type display problems. In fact, the simplest way to extend the HTMLHelp method is to define a enumtodropdownlist method, with the parameters enumerated and name.

public static mvchtmlstring enumtodropdownlist (this htmlhelper helper, Enum eenum,string name)        {            var selectlist = new list<selectlistitem> ();            var enumtype = Eenum.gettype ();            foreach (var value in Enum.getvalues (enumtype))            {                var field = Enumtype.getfield (value). ToString ());                var option = new SelectListItem () {value = value. ToString ()};                var display = field. GetCustomAttributes (typeof (DisplayAttribute), false). FirstOrDefault () as DisplayAttribute;                Option. Text = display! = null? Display. Name:value. ToString ();                Option. Selected = Equals (value, eenum);                Selectlist.add (option);            }            Return helper. DropDownList (name, selectlist);        }

Each value of the enumerated type is obtained by the Enum.getvalues method, and then the DisplayAttribute attribute is obtained by reflection. The text will then get to name as the drop-down box option. Call:

@Html. Enumtodropdownlist (Model.questiontype, "Questiontype")

Enumtodropdownlistfor is easy to implement, the key is to find the type.

  public static mvchtmlstring Enumtodropdownlistfor<tmodel, tproperty> (this htmlhelper<tmodel> HTML, Expression<func<tmodel, tproperty>> expression, object htmlattributes=null) {Modelmetadata Modelmetadata = modelmetadata.fromlambdaexpression (expression, HTML.            ViewData);            var htmlAttributes2 = anonymousobjecttohtmlattributes (htmlattributes);            var enumtype = Modelmetadata.modeltype;            var selectlist = new list<selectlistitem> (); foreach (var value in Enum.getvalues (enumtype)) {var field = Enumtype.getfield (value).                ToString ()); var option = new SelectListItem () {value = value.                ToString ()}; var display = field. GetCustomAttributes (typeof (DisplayAttribute), false).                FirstOrDefault () as DisplayAttribute; Option. Text = display! = null? Display. Name:value.                ToString (); Option.  Selected = Equals (value, Modelmetadata.model);              Selectlist.add (option); } return HTML. DropDownList (Modelmetadata.propertyname, selectlist,htmlattributes2);

The invocation is much simpler:

  @Html. enumtodropdownlistfor (model = model. Questiontype)

The result is the same, and you can extend the style to match the selection.

Helper Code

View Code

Code has been updated to: Https://github.com/stoneniqiu/Portal.MVC

Summary: Review these four methods, the partial view is the most direct, but not flexible enough, the imagefor call is simple, also the most flexible, the implementation of complex points, but can be used to expand more methods. If you want to implement a function, you need to change a few places, rely on multiple places, naturally lose flexibility, finally the implementation of the Enumtodropdownlist method is very convenient, do not need to rely on the template, and do not need to customize what features. Finally hope to help you. tks!

MVC extension html.imagefor

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.