简体   繁体   中英

How can I include more logic within a templated razor delegate?

Take the following extension method from Mr Haacked .

public static class Helpers {
  public static HelperResult RenderSection(this WebPageBase webPage, 
      string name, Func<dynamic, HelperResult> defaultContents) {
    if (webPage.IsSectionDefined(name)) {
      return webPage.RenderSection(name);
    }
    return defaultContents(null);
  }
}

The usage is as follows:

<footer>
  @this.RenderSection("Footer", @<span>This is the default!</span>)
</footer>

Quite handy, but what I would like to do for example is include some business logic within the delegate like this:

<footer>
  @this.RenderSection("Footer", @<span>
               This @if (condition) {  
                        <label>is the</label> 
                      } else {  
                        <label> default!</label> 
                      } 
              </span>)
</footer>

But no matter how I have tried to change the extension I get compilation errors when viewing the page.

How can I achieve this?

David Fowler turned me on to a really cool feature of Razor I hadn't realized made it into 1.0, Templated Razor Delegates. What's that? I'll let the code do the speaking.

@{
  Func<dynamic, object> b = @<strong>@item</strong>;
}
<span>This sentence is @b("In Bold").</span>

That could come in handy if you have friends who'll jump on your case for using the bold tag instead of the strong tag because it's “not semantic”. Yeah, I'm looking at you Damian Smile with tongue out. I mean, don't both words signify being forceful? I digress.

Note that the delegate that's generated is a Func. Also, the @item parameter is a special magic parameter. These delegates are only allowed one such parameter, but the template can call into that parameter as many times as it needs.

The example I showed is pretty trivial. I know what you're thinking. Why not use a helper? Show me an example where this is really useful. Ok, you got it!

Suppose I wrote this really cool HTML helper method for generating any kind of list.

public static class RazorExtensions {
    public static HelperResult List<T>(this IEnumerable<T> items, 
      Func<T, HelperResult> template) {
        return new HelperResult(writer => {
            foreach (var item in items) {
                template(item).WriteTo(writer);
            }
        });
    }
}

This List method accepts a templated Razor delegate, so we can call it like so.

@{
  var items = new[] { "one", "two", "three" };
}

<ul>
@items.List(@<li>@item)
</ul>

As I mentioned earlier, notice that the argument to this method, @<li>@item</li> is automatically converted into a Func<dynamic, HelperResult> which is what our method requires.

Now this List method is very reusable. Let's use it to generate a table of comic books.

@{
    var comics = new[] { 
        new ComicBook {Title = "Groo", Publisher = "Dark Horse Comics"},
        new ComicBook {Title = "Spiderman", Publisher = "Marvel"}
    };
}

<table>
@comics.List(
  @<tr>
    <td>@item.Title
    <td>@item.Publisher
  </tr>)
</table>

This feature was originally implemented to support the WebGrid helper method, but I'm sure you'll think of other creative ways to take advantage of it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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