首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何覆盖Html.ActionLink?

如何覆盖Html.ActionLink?
EN

Stack Overflow用户
提问于 2013-04-11 15:02:24
回答 3查看 4.6K关注 0票数 5

通常,我会希望呈现一个带有数据库内容的ActionLink (想象一下Id/名称组合),因此我会将以下内容放在我的视图中:

代码语言:javascript
复制
        @foreach (var row in Model)
        {
            <li>@Html.ActionLink(row.Name, "Action", "Controller", new { id = row.Id })</li>
        }

但是,如果名称是空字符串,则会引发异常。有没有办法阻止这件事。我想重写ActionLink,但是它是一个扩展,所以我不能重写。

有什么建议吗?

编辑:

首先,我不控制数据,否则我将确保Name字段是必需的,并且始终填充。不幸的是,情况并非如此。

其次,我意识到用户将没有什么可点击的,但我相信呈现一个空链接比给他们一个YSOD更好的选择。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-04-11 15:31:19

事实证明,与具有相同签名的扩展方法相比,实例方法始终是首选方法。

我能够加载一个CustomHtmlHelper并将实例方法ActionLink方法放入新的类中:

代码语言:javascript
复制
public abstract class CustomWebViewPage<T> : WebViewPage<T>
{
    public new CustomHtmlHelper<T> Html { get; set; }

    public override void InitHelpers()
    {
        Ajax = new AjaxHelper<T>(ViewContext, this);
        Url = new UrlHelper(ViewContext.RequestContext);

        //Load Custom Html Helper instead of Default
        Html = new CustomHtmlHelper<T>(ViewContext, this);
    }
}

HtmlHelper如下所示(从Reflector复制的ActionLink方法没有LinkText错误检查):

代码语言:javascript
复制
public class CustomHtmlHelper<T> : HtmlHelper<T>
{
    public CustomHtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer) :
        base(viewContext, viewDataContainer)
    {
    }

    //Instance methods will always be called instead of extension methods when both exist with the same signature...

    public MvcHtmlString ActionLink(string linkText, string actionName)
    {
        return ActionLink(linkText, actionName, null, new RouteValueDictionary(), new RouteValueDictionary());
    }

    public MvcHtmlString ActionLink(string linkText, string actionName, object routeValues)
    {
        return ActionLink(linkText, actionName, null, new RouteValueDictionary(routeValues), new RouteValueDictionary());
    }

    public MvcHtmlString ActionLink(string linkText, string actionName, string controllerName)
    {
        return ActionLink(linkText, actionName, controllerName, new RouteValueDictionary(), new RouteValueDictionary());
    }

    public MvcHtmlString ActionLink(string linkText, string actionName, RouteValueDictionary routeValues)
    {
        return ActionLink(linkText, actionName, null, routeValues, new RouteValueDictionary());
    }

    public MvcHtmlString ActionLink(string linkText, string actionName, object routeValues, object htmlAttributes)
    {
        return ActionLink(linkText, actionName, null, new RouteValueDictionary(routeValues), AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public MvcHtmlString ActionLink(string linkText, string actionName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
    {
        return ActionLink(linkText, actionName, null, routeValues, htmlAttributes);
    }

    public MvcHtmlString ActionLink(string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
    {
        return ActionLink(linkText, actionName, controllerName, new RouteValueDictionary(routeValues), AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public MvcHtmlString ActionLink(string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
    {
        return MvcHtmlString.Create(GenerateLink(ViewContext.RequestContext, RouteCollection, linkText, null, actionName, controllerName, routeValues, htmlAttributes));
    }

    public MvcHtmlString ActionLink(string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, object routeValues, object htmlAttributes)
    {
        return ActionLink(linkText, actionName, controllerName, protocol, hostName, fragment, new RouteValueDictionary(routeValues), AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public MvcHtmlString ActionLink(string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
    {
        return MvcHtmlString.Create(GenerateLink(ViewContext.RequestContext, RouteCollection, linkText, null, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttributes));
    }
}

最后,将pageBaseType int Views/Web.config文件设置为使用新的自定义WebViewPage:

代码语言:javascript
复制
  <system.web.webPages.razor>
    ...
    <pages pageBaseType="Fully.Qualified.Namespace.CustomWebViewPage">
    ...
    </pages>
  </system.web.webPages.razor>

希望这能帮到别人。

票数 10
EN

Stack Overflow用户

发布于 2013-04-11 15:06:19

您将遇到的问题是,如果名称为空,则UI中的用户没有什么可单击的。示例:<a href="someUrl"></a>没有提供可点击的对象。

更好的方法可能是,如果您可以为那些具有空字符串的行提供默认的"No Name“字符串。

代码语言:javascript
复制
@foreach (var row in Model)
        {
            <li>@Html.ActionLink(string.isNullOrEmpty(row.Name) ? "No Name" : row.Name, "Action", "Controller", new { id = row.Id })</li>
        }

编辑

如果不想在每个@Html.ActionLink中添加条件,则可以创建自己的@Html.Helper。

代码语言:javascript
复制
 public static IHtmlString ActionLinkCheckNull(this HtmlHelper htmlHelper, string linkText, string action, string controller, object routeValues, object htmlAttributes)
        {
            var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
            var anchor = new TagBuilder("a") { InnerHtml = string.IsNullOrEmpty(linkText) ? "No Name", linktext };
            anchor.Attributes["href"] = urlHelper.Action(action, controller, routeValues);
            anchor.MergeAttributes(new RouteValueDictionary(htmlAttributes));
            return MvcHtmlString.Create(anchor.ToString());
        }

然后,在视图文件夹web.config中,添加对您放置此扩展的命名空间的引用,这样您就不必在每个视图的顶部都有一个using语句。示例:

代码语言:javascript
复制
<add namespace="Core.Extensions"/>

然后在您的视图中,使用

代码语言:javascript
复制
 @Html.ActionLinkCheckNull(row.Name, "Action", "Controller", new { id = row.Id })
票数 4
EN

Stack Overflow用户

发布于 2013-04-11 15:11:37

为了更具体地说明汤米的意思,我想包括一个最终被称为被保护的方法:

代码语言:javascript
复制
private static string GenerateLinkInternal(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, bool includeImplicitMvcValues)
{
    string value = UrlHelper.GenerateUrl(routeName, actionName, controllerName, protocol, hostName, fragment, routeValues, routeCollection, requestContext, includeImplicitMvcValues);
    TagBuilder tagBuilder = new TagBuilder("a")
    {
        InnerHtml = (!string.IsNullOrEmpty(linkText)) ? HttpUtility.HtmlEncode(linkText) : string.Empty
    };
    tagBuilder.MergeAttributes<string, object>(htmlAttributes);
    tagBuilder.MergeAttribute("href", value);
    return tagBuilder.ToString(TagRenderMode.Normal);
}

因此,由于您正在构建链接,外部方法将抛出一个异常,因为将不会在屏幕上显示任何文本。的代码如下所示:

代码语言:javascript
复制
public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
{
    if (string.IsNullOrEmpty(linkText))
    {
        throw new ArgumentException(MvcResources.Common_NullOrEmpty, "linkText");
    }
    return MvcHtmlString.Create(HtmlHelper.GenerateLink(htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection, linkText, null, actionName, controllerName, routeValues, htmlAttributes));
}

从技术上讲,代码不需要受到保护,但它是一种特性。

这里有一个解决办法,但是您需要像这样构建自己的ActionLink扩展方法,并将其放在项目的某个代码文件中:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Web.Mvc.Resources;
using System.Web.Routing;
namespace System.Web.Mvc.Html
{
    public static class MyLinkExtensions
    {
        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, int identifier)
        {
            return htmlHelper.ActionLink(string.IsNullOrEmpty(linkText) ? "some default text" : linkText, actionName, controllerName, new { id = identifier });
        }
    }
}

现在你的标记看起来是这样的:

代码语言:javascript
复制
@foreach (var row in Model)
{
    <li>@Html.ActionLink(row.Name, "Action", "Controller", row.Id)</li>
}

您已经封装了转帐以确定linkText的状态,但仍然在一行中呈现您的链接。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15952240

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档