I want to create a helper that i can add content between the brackets just like Helper.BeginForm() does. I wouldnt mind create a Begin, End for my helper but it's pretty simple and easy to do it that way.
basically what i am trying to do is wrapping content between these tags so they are rendered already formatted
something like
@using Html.Section("full", "The Title")
{
This is the content for this section
<p>More content</p>
@Html.TextFor("text","label")
etc etc etc
}
the parameters "full" is the css id for that div and "the title" is the title of the section.
Is there a better way to achieve this other than doing what i am trying to do?
thanks in advance for any help.
It's totally possible. The way this is done in MVC with things like Helper.BeginForm
is that the function must return an object that implements IDisposable
.
The IDisposable
interface defines a single method called Dispose
which is called just before the object is garbage-collected.
In C#, the using
keyword is helpful to restrict the scope of an object, and to garbage-collect it as soon as it leaves scope. So, using it with IDisposable
is natural.
You'll want to implement a Section
class which implements IDisposable
. It will have to render the open tag for your section when it is constructed, and render the close tag when it is disposed. For example:
public class MySection : IDisposable {
protected HtmlHelper _helper;
public MySection(HtmlHelper helper, string className, string title) {
_helper = helper;
_helper.ViewContext.Writer.Write(
"<div class=\"" + className + "\" title=\"" + title + "\">"
);
}
public void Dispose() {
_helper.ViewContext.Writer.Write("</div>");
}
}
Now that the type is available, you can extend the HtmlHelper.
public static MySection BeginSection(this HtmlHelper self, string className, string title) {
return new MySection(self, className, title);
}
Here is a little util I wrote to do this. It is a little more generic so you can use it for any tag and with any attributes. It is setup as an extension method on HtmlHelper so you can use it right from within Razor as well as from within code.
public static class WrapUtil
{
public static IDisposable BeginWrap(this HtmlHelper helper, string tag, object htmlAttributes)
{
var builder = new TagBuilder(tag);
var attrs = GetAttributes(htmlAttributes);
if (attrs != null)
{
builder.MergeAttributes<string, object>(attrs);
}
helper.ViewContext.Writer.Write(builder.ToString(TagRenderMode.StartTag));
return new WrapSection(helper, builder);
}
private static IDictionary<string, object> GetAttributes(object htmlAttributes)
{
if (htmlAttributes == null)
{
return null;
}
var dict = htmlAttributes as IDictionary<string, object>;
if (dict != null)
{
return dict;
}
return HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
}
private class WrapSection : IDisposable
{
private readonly HtmlHelper _Helper;
private readonly TagBuilder _Tag;
public WrapSection(HtmlHelper helper, TagBuilder tag)
{
_Helper = helper;
_Tag = tag;
}
public void Dispose()
{
_Helper.ViewContext.Writer.Write(_Tag.ToString(TagRenderMode.EndTag));
}
}
}