tags:

views:

601

answers:

2

Hello guys,

I'm writing my first asp.net mvc application and I have a question about custom Html helpers:

For making a form, you can use:

<% using (Html.BeginForm()) {%>
   *stuff here*
<% } %>

I would like to do something similiar with a custom html helper. In other words, I want to change:

           Html.BeginTr();
           Html.Td(day.Description);
           Html.EndTr();

into:

       using Html.BeginTr(){
            Html.Td(day.Description);
       }

Is this possible?

+3  A: 

If you look at the source for the ASP.NET MVC (available on Codeplex), you'll see the implementation of the BeginForm eventually calls down to the following code:

static MvcForm FormHelper(this HtmlHelper htmlHelper, string formAction, FormMethod method, IDictionary<string, object> htmlAttributes)
{
    TagBuilder builder = new TagBuilder("form");
    builder.MergeAttributes<string, object>(htmlAttributes);
    builder.MergeAttribute("action", formAction);
    builder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
    htmlHelper.ViewContext.HttpContext.Response.Write(builder.ToString(TagRenderMode.StartTag));

    return new MvcForm(htmlHelper.ViewContext.HttpContext.Response);
}

The MvcForm class implements IDisposable, in it's dispose method is writes the </form> to the response.

So, what you'd need to do is write the tags you want out in the helper method and return an object that implements IDisposable...in it's dispose method close the tag off.

Kieron
+7  A: 

Here is a possible reusable implementation in c# :

class DisposableHelper : IDisposable
{
    private Action end;

    // When the object is create, write "begin" function
    DisposableHelper(Action begin, Action end)
    {
        this.end = end;
        begin();
    }

    // When the object is disposed (end of using block), write "end" function
    public void Dispose()
    {
        end();
    }
}

public static class DisposableExtensions
{
    public static IDisposable DisposableTr(this HtmlHelper htmlHelper)
    {
        return new DisposableHelper(
            () => htmlHelper.BeginTr(),
            () => htmlHelper.EndTr()
        );
    }
}

In this case, BeginTr and EndTr directly write in the response stream. If you use extension methods that return a string, you'll have to output them using :

htmlHelper.ViewContext.HttpContext.Response.Write(s)
ybo
pweh.. and I thought this was going to be easy.. Thanks for your effort.
Thomas Stock
It was just a quick and dirty implementation. The "begin" delegate can be called directly in your extension method and the DisposableHelper class is reusable for other extensions
ybo
Ok thanks, I'll take a better look at this later on.
Thomas Stock
Not sure what isn't easy about this - it's a pretty elegant solution really.
Charles Boyung