12

我想创建一个可以像这样使用的助手

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

例如,这应该返回

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

如果是@Html.MyHelperFor(m => m.MailID) 这应该返回

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

我认为,我应该能够访问辅助方法中的属性名称来制作这种类型的帮助器。

我怎样才能做到这一点?

4

4 回答 4

22

您可以执行类似的操作(以下内容也将采用额外的 HTML 属性)。

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());
}
于 2013-08-27T17:56:05.973 回答
5

您可以使用以下FromLambaExpression方法ModelMetadata

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);
        }
    }
}

该类ModelMetadata位于System.Web.Mvc命名空间中。该FromLambdaExpression方法是内置助手使用的方法,因此您可以确保您的助手与内置助手的功能相同。通过将CustomHelpers类放在System.Web.Mvc.Html命名空间内,您可以像访问其他助手一样访问您的助手,即@Html.MyHelperFor().

于 2013-08-27T17:49:39.447 回答
2

这应该让你开始。此函数直接返回属性名称,但您应该能够通过一些工作将其转换为您正在寻找的扩展名。此示例具有正确的方法签名和对 ExpressionHelper 的调用以获取您的属性的名称。

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

        return new MvcHtmlString(expressionName);
    }
于 2013-08-27T17:47:41.957 回答
1

跟进 mattytommo 的回答,这很好用,但在与复杂对象一起使用时只有一个小问题,例如,如果您将此代码用于 EditorTemplate 中的属性。

代替

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

如果使用 MVC4,您可以将其更改为

var propertyName = helper.NameFor(expression);

或对于 MVC3 及以下

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);

完整代码:

    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());
    }
于 2015-06-03T20:05:44.223 回答