为Razor改编自定义HTML助手(使用HtmlTextWriter,因此返回void) [英] Adapting a Custom Html Helper for Razor (it uses HtmlTextWriter so returns void)

查看:86
本文介绍了为Razor改编自定义HTML助手(使用HtmlTextWriter,因此返回void)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常漂亮的菜单HTML助手,用于WebFormViewEngine视图.此引擎使您的助手可以返回void,并且仍然可以使用:

I have a very nifty menu Html helper written for WebFormViewEngine views. This engine allows your helpers to return void, and still be able to use:

@Html.Theseus

这对我的助手非常有用,因为它随后可以使用HtmlTextWriter渲染菜单,该菜单直接渲染到输出流.

This is great for my helper, because it can then render the menu using HtmlTextWriter, that renders directly to the output stream.

但是,在Razor视图中,期望HTML帮助器返回一个值(通常是MvcHtmlString),该值将被添加到输出中.差异小,后果大.

In Razor views, however, the Html helpers are expected to return a value (usually MvcHtmlString) which is what gets added to the output. Small difference, big consequence.

正如GvS向我指出的那样,有一种解决方法(请参阅

There is a way around this, as pointed out to me by GvS (see ASP.NET MVC 2 to MVC 3: Custom Html Helpers in Razor) as follows:

如果帮助程序返回void,请执行以下操作:

If the helper returns void, then do the following:

@{Html.Theseus;}

(本质上,您只是在调用方法,而不是呈现到视图中.)

(Essentially, you are just calling the method, rather than rendering into the view).

虽然仍然很整洁,但这与@ Html.Theseus不太一样.所以...

Whilst still neat, this is not quite the same as @Html.Theseus. So...

我的代码很复杂,但是效果很好,因此不愿进行重大编辑,即用另一个编写器替换HtmlTextWriter.代码片段如下:

My code is complex but works very well, so am loath to go through major edits, ie, replacing the HtmlTextWriter with another writer. A snippet of the code goes like:

writer.AddAttribute(HtmlTextWriterAttribute.Href, n.Url);
writer.AddAttribute(HtmlTextWriterAttribute.Title, n.Description);
writer.RenderBeginTag(HtmlTextWriterTag.A);
writer.WriteEncodedText(n.Title);
writer.RenderEndTag();

// Recursion, if any
// Snip off the recursion at this level if specified by depth
// Use a negative value for depth if you want to render the entire sitemap from the starting node

    if ((currentDepth < depth) || (depth < 0))
    {
         if (hasChildNodes)
         {
              // Recursive building starts here

              // Open new ul tag for the child nodes 
              // "<ul class='ChildNodesContainer {0} Level{1}'>"; 
              writer.AddAttribute(HtmlTextWriterAttribute.Class, "Level" + currentDepth.ToString());
              writer.RenderBeginTag(HtmlTextWriterTag.Ul);

              // BuildMenuLevel calls itself here to 
              // recursively traverse the sitemap hierarchy, 
              // building the menu as I go.
              // Note: this is where I increase the currentDepth variable!
               BuildChildMenu(currentDepth + 1, depth, n, writer);

              // Close ul tag for the child nodes
              writer.RenderEndTag();
          }
    }

用TagBuilders重写并不是一件有趣的事情.就目前而言,它呈现任何类型的菜单,包括我的4guysfromrolla文章中所述的增量导航": 使用ASP.NET实现增量导航

It wouldn't be fun to re write with TagBuilders. As it stands, it renders any type of menu, including the "Incremental Navigation" as described in my 4guysfromrolla article: Implementing Incremental Navigation with ASP.NET

我想我可以返回一个空的MvcHtmlString,但这几乎是hack的定义...

I guess I could return an empty MvcHtmlString, but that is pretty much the definition of a hack...

唯一的选择是进入日落,使用TagBuilder重写帮助程序以构建每个标签,将其添加到StringBuilder,然后构建下一个标签,依此类推,然后使用StringBuilder实例创建MvcHtmlString.严重的丑陋,除非我可以做...

The only alternative is to head off into the sunset and rewrite the helper using the TagBuilder to build each tag, add that to a StringBuilder, then build the next tag, etc, and then use the StringBuilder instance to create the MvcHtmlString. Seriously ugly, unless I could do something like...

有没有办法:

停止将HtmlTextWriter呈现到流中,而将其像StringBuilder一样使用,在过程结束时我用来创建MvcHtmlString(或HtmlString)?

Stop the HtmlTextWriter rendering to the stream and instead use it like a StringBuilder that at the end of the process I use to create an MvcHtmlString (or HtmlString)?

听起来不太可能,即使我写...

Sounds unlikely, even as I write...

HtmlTextWriter的伟大之处在于,您可以构建大量的标签,而不是像使用TagBuilder一样一一构建.

The great thing about the HtmlTextWriter is that you can build large quantities of tags, instead of building them one by one as with a TagBuilder.

推荐答案

与您为

Contrary to the responses you received for your other question Razor does not require that you return an HtmlString. The problem with your code right now is that you are writing directly to the response stream. Razor executes things inside-out which means that you can mess up the response order (see a similar question).

因此,在您的情况下,您可能可以执行此操作(尽管我尚未对其进行测试):

So in your case you could probably do this (though i haven't tested it):

public static void Theseus(this HtmlHelper html)
{
    var writer = new HtmlTextWriter(html.ViewContext.Writer);
    ...
}

编辑(后续处理您的评论):

Edit (follow up to address your comments):

HTML Helpers完全能够直接返回HtmlString或void并将其写入上下文编写器.例如,Html.PartialHtml.RenderPartial在Razor中都可以正常工作.我认为您感到困惑的是调用一个版本而不是另一个版本所需的语法.

Html Helpers are perfectly capable of either returning a HtmlString directly or void and writing to the context writer. For example, both Html.Partial and Html.RenderPartial work fine in Razor. I think what you are confusing is the syntax required to call one version and not the other.

例如,考虑一个Aspx视图:

For example, consider an Aspx view:

<%: Html.Partial("Name") %>
<% Html.RenderPartial("Name") %>

您以不同的方式调用每个方法.如果您四处翻转,事情将无法正常工作.在剃刀中也是如此:

You call each method differently. If you flip things around, things will just not work. Similarly in Razor:

@Html.Partial("Name")
@{ Html.RenderPartial("Name"); }

现在,恰好碰巧是,与Aspx相比,Razor中使用void助手的语法更加冗长.但是,两者都很好.除非您通过问题在于html帮助程序无法返回void"来表示其他含义.

Now it just so happens that the syntax to use a void helper is a lot more verbose in Razor compared to Aspx. However, both work just fine. Unless you meant something else by "the issue is with a html helper not being able to return void".

顺便说一句,如果您真的想使用以下语法来调用您的助手:@Html.Theseus(),您可以这样做:

By the way, if you really want to call your helper using this syntax: @Html.Theseus() you could do this:

public static IHtmlString Theseus(this HtmlHelper html)
{
    var writer = new HtmlTextWriter(html.ViewContext.Writer);
    ...
    return new HtmlString("");
}

但这有点骇人听闻.

这篇关于为Razor改编自定义HTML助手(使用HtmlTextWriter,因此返回void)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆