2011-08-25 13 views
22

Desidero creare un helper in grado di aggiungere contenuto tra parentesi, proprio come fa Helper.BeginForm(). Non mi dispiacerebbe creare un Begin, End for my helper ma è piuttosto semplice e facile da fare in quel modo.Creazione di MVC3 Razor Helper come Helper.BeginForm()

Fondamentalmente quello che sto cercando di fare è avvolgere contenuto tra questi tag in modo che siano resi già formattati

qualcosa come

@using Html.Section("full", "The Title") 
{ 
This is the content for this section 
<p>More content</p> 
@Html.TextFor("text","label") 
etc etc etc 
} 

i parametri "pieno" è l'id CSS per quel div e " il titolo "è il titolo della sezione.

C'è un modo migliore per ottenere questo oltre a fare quello che sto cercando di fare?

grazie in anticipo per qualsiasi aiuto.

risposta

36

È totalmente possibile. Il modo in cui questo viene fatto in MVC con cose come Helper.BeginForm è che la funzione deve restituire un oggetto che implementa IDisposable.

Il IDisposable interface definisce un singolo metodo chiamato Dispose che viene chiamato appena prima che l'oggetto sia sottoposto a garbage collection.

In C#, la parola chiave using è utile per limitare l'ambito di un oggetto e per eseguire la raccolta dei dati inutili non appena esce dall'ambito. Quindi, usarlo con IDisposable è naturale.

Si desidera implementare una classe Section che implementa IDisposable. Dovrà eseguire il rendering del tag aperto per la sezione al momento della sua costruzione e renderizzare il tag close quando viene eliminato. Per esempio:

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

Ora che il tipo è disponibile, è possibile estendere la HtmlHelper.

public static MySection BeginSection(this HtmlHelper self, string className, string title) { 
    return new MySection(self, className, title); 
} 
+0

si dovrebbe cambiare il tuo nome a whatgoodisadispose !!! :) grazie mille. sapevo che dovevi implementare iDisposable in modo che una classe potesse essere utilizzata con {} ma non ci hai mai pensato per un secondo. grazie mille ancora una volta –

+1

Ah, Writer, quello ha fatto il trucco. –

4

Ecco un piccolo util che ho scritto per fare questo. È un po 'più generico, quindi puoi usarlo per qualsiasi tag e con qualsiasi attributo. È configurato come un metodo di estensione su HtmlHelper in modo da poterlo usare direttamente da Razor e dal codice.

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)); 
     } 
    } 
} 
Problemi correlati