Creating custom Html Helper: MyHelperFor

2019-02-02 02:20发布

I would like to create a helper that can be used like

@Html.MyHelperFor(m => m.Name)

this should return for example

<span name="Name" data-something="Name"></span>

if it is @Html.MyHelperFor(m => m.MailID) This should return

<span name="MailID" data-something="MailID"></span>

I should be able to access the Property name in the helper method to make this type of helper ,I think.

How can I do this?

4条回答
乱世女痞
2楼-- · 2019-02-02 03:03

You can do something like (the following will take additional HTML attributes too).

public static MvcHtmlString MyHelperFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression, object htmlAttributes = null)
{
    var data = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
    string propertyName = data.PropertyName;
    TagBuilder span = new TagBuilder("span");
    span.Attributes.Add("name", propertyName);
    span.Attributes.Add("data-something", "something");

    if (htmlAttributes != null)
    {
        var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
        span.MergeAttributes(attributes);
    }

    return new MvcHtmlString(span.ToString());
}
查看更多
三岁会撩人
3楼-- · 2019-02-02 03:11

Following up on mattytommo's answer, this works great but there is only a small problem when used with complex objects, such as if you are using this code for a property inside an EditorTemplate.

Instead of

var data = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
string propertyName = data.PropertyName;

If using MVC4, you can change it to

var propertyName = helper.NameFor(expression);

or for MVC3 and below

var propertyName = expression.Body.ToString();
propertyName = propertyName.Substring(propertyName.IndexOf(".") + 1);
if (!string.IsNullOrEmpty(helper.ViewData.TemplateInfo.HtmlFieldPrefix))
    propertyName = string.Format("{0}.{1}", helper.ViewData.TemplateInfo.HtmlFieldPrefix, propertyName);

Full code:

    public static MvcHtmlString MyHelperFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression, object htmlAttributes = null)
    {
        var propertyName = expression.Body.ToString();
        propertyName = propertyName.Substring(propertyName.IndexOf(".") + 1);
        if (!string.IsNullOrEmpty(helper.ViewData.TemplateInfo.HtmlFieldPrefix))
            propertyName = string.Format("{0}.{1}", helper.ViewData.TemplateInfo.HtmlFieldPrefix, propertyName);

        TagBuilder span = new TagBuilder("span");
        span.Attributes.Add("name", propertyName);
        span.Attributes.Add("data-something", propertyName);

        if (htmlAttributes != null)
        {
            var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
            span.MergeAttributes(attributes);
        }

        return new MvcHtmlString(span.ToString());
    }
查看更多
Viruses.
4楼-- · 2019-02-02 03:17

You can use the FromLambaExpression method from ModelMetadata like this:

namespace System.Web.Mvc.Html
{
    public static class CustomHelpers
    {
        public static MvcHtmlString MyHelperFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
        {
            var metaData = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
            var name = metaData.PropertyName;
            // create your html string, you could defer to DisplayFor to render a span or
            // use the TagBuilder class to create a span and add your attributes to it
            string html = "";
            return new MvcHtmlString(html);
        }
    }
}

The ModelMetadata class is in the System.Web.Mvc namespace. The FromLambdaExpression method is what the built in helpers use so then you can be sure your helper will function the same as the built in helpers. By placing the CustomHelpers class inside the System.Web.Mvc.Html namespace you can then access your helper like you would the other helpers, i.e. @Html.MyHelperFor().

查看更多
对你真心纯属浪费
5楼-- · 2019-02-02 03:22

This should get you started. This function directly returns the property name but you should be able to convert this into the extension you are looking for with a little work. This example has the correct method signature and the call to ExpressionHelper to get the name of your property.

    public static MvcHtmlString MyHelperFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression)
    {
        string expressionName = ExpressionHelper.GetExpressionText(expression);

        return new MvcHtmlString(expressionName);
    }
查看更多
登录 后发表回答