In ASP.NET RAZOR MVC5 there is such a great helper as

Html.BeginForm() 

It can be written as

 @Html.BeginForm() ... @Html.EndForm() 

So and

 @using (Html.BeginForm()) { ... } 

How to create a custom helper on this principle. For example, I need a div block, the block is not bare, but there are some basic elements in it, let's say five links. I need to duplicate this block all the time, in addition to the fixed five links, I need to push a bunch of other elements inside, it could be a button / table / picture / etc. So, how can this be implemented using the same beautiful curly braces, rather than writing Html.MyPerfectDivStart () and Html.MyPerfectDivEnd ()

There is an option to use MvcHtmlString and pass as a List<MvcHtmlString> parameter from various other components created by me. But it looks ugly!

  • Create your own helper, enter one of the methods in @using , and the closing @using - in Dispose. You know that using is syntactic sugar? - AK
  • Then, after all, the method should be created as a separate non-static class? Otherwise, how to set the dispose method - Tima
  • one
    Oh yes. Look at the class System.Web.Mvc.Html.MvcForm there obviously. - AK

1 answer 1

With the forms you can not write

 @Html.BeginForm() ... @Html.EndForm() 

Because microsoft in EndForm returns void , not MvcHtmlString , and you get an error:

Error CS0029 Cannot implicitly convert type 'void' to 'object'

And you cannot have two BeginForm overloads, one of which returns a string (for a call without using), and the second - new MvcDiv (needed for deployment in a using).

How to make a helper similar to System.Web.Mvc.Html.MvcForm for a call via using .

First, the extension for opening / closing:

 public static class MyDivHelper { public static MvcDiv BeginDiv(this HtmlHelper htmlHelper) { htmlHelper.ViewContext.Writer.Write("<div style='asdf'>"); return new MvcDiv(htmlHelper.ViewContext); } internal static void EndDiv(ViewContext viewContext) { viewContext.Writer.Write("</div>"); } } 

Secondly, disposing for the closing div 'a:

 public class MvcDiv : IDisposable { private readonly ViewContext _viewContext; public MvcDiv(ViewContext viewContext) { if (viewContext == null) throw new ArgumentNullException(nameof(viewContext)); this._viewContext = viewContext; } public void Dispose() { MyDivHelper.EndDiv(this._viewContext); } } 

Example of use:

 @using (Html.BeginDiv()) { } 
  • four
    1. Why call GC.SuppressFinalize if there is still no finalizer? 2. Why implement the Dispose bool pattern if there are no unmanaged resources and never will be? Note, the flag is not even checked. And business logic itself is incompatible with the finalizer. - Qwertiy
  • one
    I will support Qwertiy - Dispose should be simplified. Well this is not really a resource cleanup, but simply a sugar to call EndDiv. - Pavel Mayorov
  • one
    In addition, it makes sense to make MvcDiv a structure (according to the principle “it costs us nothing, and one allocation will be less”) - Pavel Mayorov
  • one
    @PavelMayorov allocation on the stack is possible only if the object lives within the context where it was created. If it goes to the outside - this number will not work. In this case, we return the value, and we also create it using the constructor. Thus, it will not even initobj , namely newobj even if you make a structure. Those. no benefits. Before being engaged in micro-optimization, it is necessary to figure out how everything works, and whether it is necessary to optimize at all in this particular case. - lorond
  • one
    @PavelMayorov Memory can be allocated either on the stack or on the heap. There is a free allocation on the stack - it is possible, but when you return from the method, the same free destruction will automatically occur. We need to keep the value, which means we cannot allocate on the stack. It remains only a bunch. By the way, memory allocation in the zero generation is also sooooo easy operation (I recommend watching the clr sources). Well, in the appendage: blogs.msdn.microsoft.com/ericlippert/2010/10/11/… ... - lorond