Custom Html Helper adaptation for Razor (it uses HtmlTextWriter, therefore returns void)

Problem

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

@Html.Theseus

This is great for my helper because it can display a menu using HtmlTextWriter, which displays the output stream directly.

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

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

If the helper returns void, do the following:

@{Html.Theseus;}

(Essentially, you just call the method, not visualize it in the form). A.

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

My code is complex, but it works very well, so I can not go through the main changes, i.e. replace HtmlTextWriter with another author. The code snippet is as follows:

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

It would not be fun to write with TagBuilders. In its current form, it displays any menu, including Incremental Navigation, as described in 4guysfromrolla: Implementing Incremental Navigation Using ASP.NET

Parameters:

I think I could return an empty MvcHtmlString, but this is pretty much a hack definition ...

- TagBuilder , StringBuilder, .., StringBuilder MvcHtmlString. , - ...

:

:

HtmlTextWriter StringBuilder, , MvcHtmlString ( HtmlString)?

, ...

PS:

HtmlTextWriter , , , TagBuilder.

+3
1

, Razor , HtmlString. , . Razor , , (. ).

, ( ):

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

( ):

Html HtmlString , void, . , Html.Partial, Html.RenderPartial Razor. , , , .

, Aspx:

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

-. , . Razor:

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

, void Razor Aspx. . - , " , html- ".

, , : @Html.Theseus() :

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

.

+7

All Articles