繁体   English   中英

如何重载MVC HtmlHelper扩展方法

[英]How to Overload MVC HtmlHelper Extension Methods

我正在尝试注册自定义MVC HtmlHelper扩展。

我已经为扩展方法创建了适当的静态类和静态方法,但是如何在我的视图中注册/导入/使用该命名空间,因此对于@Html.SomeMethod ,它显示为某些给定方法的扩展方法。

在Asp.Net WebForms中,我可以简单地添加:

<%@ Import Namespace="MyExtensionNamespace.MyExtensionClassName" %>

如何对MVC进行相同操作,以便我的HTML Helper扩展方法可以正确解析,并且该方法将显示在IntelliSense中?

明确地说,我仅尝试向现有方法添加扩展,以便它们将接受不同的参数作为参数,例如System.Reflection.PropertyInfo

例如,我想将System.Reflection.PropertyInfo的扩展方法扩展为@Html.Label

    @{
    System.Reflection.PropertyInfo[] props = typeof(MyClaimDto).GetProperties();
    foreach (var prop in props)
    {
        if (prop.PropertyType != typeof(MyNamespace.DynamicDictionary))
        {
            <div class="form-group">
                @Html.LabelFor(prop, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.Editor(prop.Name, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.Hidden("Utility." + prop.PropertyType.FullName, new { @class = "form-control" } )
                    @Html.Hidden("PlaceHolder." + prop.Name, new { @class = "form-control" } )
                    @Html.ValidationMessage(prop.Name, "", new { @class = "text-danger" })
                </div>
            </div>
        }
    }


}

但是VS告诉我,我的通话仍然有一个错误,提示无法推断出Type Arguments:

在此处输入图片说明

这是我的扩展程序的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Reflection;
using System.Linq.Expressions;
namespace EFWCF.Extensions
{
    public static class LabelExtensions
    {
        public static MvcHtmlString LabelFor<PropertyInfo, TValue>(this HtmlHelper<PropertyInfo> html, Expression<Func<PropertyInfo, TValue>> expression)
        {
            var type = expression.Type;
            MvcHtmlString result = new MvcHtmlString(type.FullName);
            return result;
        }
    }
}

如果我给方法一个不同的名字,它将解决:

public static MvcHtmlString PropertyLabelFor<PropertyInfo, TValue>(this HtmlHelper<PropertyInfo> html)
{
    var type = expression.Type;
    MvcHtmlString result = new MvcHtmlString(type.FullName);
    return result;
}

和:

 @Html.PropertyLabelFor(prop)

但是我希望能够为其他类型调用现有的@Html方法。

您可以通过以下两种方式引用名称空间:

直接在视图中:

@using YourProject.HtmlHelpers;

或者,您可以在Views/web.config文件中添加对该名称空间的引用,从而无需在视图顶部添加using

<system.web.webPages.razor>
  <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  <pages pageBaseType="System.Web.Mvc.WebViewPage">
    <namespaces>
      <add namespace="System.Web.Mvc" />
      <add namespace="System.Web.Mvc.Ajax" />
      <add namespace="System.Web.Mvc.Html" />
      <add namespace="System.Web.Routing" />
      <!-- Reference here -->
      <add namespace="YourProject.HtmlHelpers" />
    </namespaces>
  </pages>
</system.web.webPages.razor>

无法从用法中推断出类型实参,这意味着在将标识符分配为方法类型实参的过程中发生了通用类型不匹配。 在这里,您的自定义扩展方法将System.Reflection.PropertyInfo定义为TModel替代:

public static MvcHtmlString LabelFor<PropertyInfo, TValue>(this HtmlHelper<PropertyInfo> html, Expression<Func<PropertyInfo, TValue>> expression)
{
    var type = expression.Type;
    MvcHtmlString result = new MvcHtmlString(type.FullName);
    return result;
}

这是一个标准的HtmlHelper.LabelFor方法:

public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
{
   ...
}

根据我的观察,Razor似乎使用HtmlHelper.LabelFor而不是使用其自定义扩展方法重载,因此,在视图页面中,您尝试将PropertyInfo作为标准LabelFor上的expression参数分配,该参数期望使用lambda表达式,从而导致CS0411错误。

要解决此问题,可以将自定义扩展方法名称更改为另一个有效名称(避免命名冲突),或者通过对System.Reflection.PropertyInfo进行类型检查,为标准LabelFor创建重载,例如以下示例:

// note that you still require to insert PropertyInfo as a lambda expression here
public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
{
    var modelType = typeof(TModel);
    var propertyInfo = typeof(System.Reflection.PropertyInfo);
    if (modelType.IsAssignableFrom(propertyInfo))
    {
        var type = expression.Type;
        var tag = new TagHelper("label");
        var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
        tag.MergeAttributes(attributes);
        tag.SetInnerText(type.FullName); // set inner text between label tag
        return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
    }
    else
    {
        // return another value, e.g. return MvcHtmlString.Empty
    }
}

注意:如果您通过使用与LabelFor不同的方法名来采用第一个选项, LabelFor不想将lambda表达式用作PropertyInfo赋值,则只需删除Expression<Func<PropertyInfo, TValue>>并直接使用PropertyInfo即可,如下所示:

public static MvcHtmlString PropertyLabelFor<TModel>(this HtmlHelper<TModel> html, PropertyInfo propertyInfo, object htmlAttributes)
{
    var type = propertyInfo.GetType();
    var tag = new TagHelper("label");
    var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
    tag.MergeAttributes(attributes);
    tag.SetInnerText(type.FullName); // set inner text between label tag
    return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
}

然后,在Views目录内的web.config上使用辅助名称空间的引用,这样就无需在视图页面中使用@using指令:

<system.web.webPages.razor>
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Web.UI.WebControls" />
        ...
        <add namespace="EFWCF.Extensions.LabelExtensions" /> <-- add this line
      </namespaces>
    </pages>
</system.web.webPages.razor>

其他参考:

如何覆盖@ Html.LabelFor模板?

如何扩展MVC3 Label和LabelFor HTML帮助器?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM