2012-01-31 12 views
10

Ni siquiera estoy seguro de si esto es posible, pero pensé que verificaría si hay alguna forma de hacerlo más fácil.MVC 3 Razor, Ayudantes con marcado personalizado/sección

En primer lugar, tengo algunas marcas se repite en mi sitio que tiene este aspecto:

<div class="module"> 
    <h3>Title</h3> 
    <div> 
     <p>Information goes here</p> 
    </div> 
</div> 

Lo que quiero hacer es envolver esto en una especie de ayudante/sección para que yo pudiera hacer algo como esto

@MyHelper("This is my Title") { 
    <p>Here is my custom markup</p> 
} 

Entonces, cuando se hace, sería inyectar el título pasó a través del parámetro entre la <h3></h3> y el marcado de encargo en los divs. El marcado personalizado podría ser cualquier cosa, desde prueba, para formar controles, hasta una vista parcial. ¿Es esto algo que es posible?

Respuesta

12

Bueno, esta es una forma "estándar" de hacer algo parecido, usando una extensión de ayuda HTML. Una versión muy simple de lo que hace Html.BeginForm().

Enfoque: Simplemente devuelva un IDisposable, y deje que la declaración using se encargue del resto.

Esto es solo un ejemplo del concepto (aunque funciona). No está diseñado para su reutilización inmediata. Escrito rápidamente con muchos atajos, no con código de producción, muchas oportunidades de mejora y optimización, puede tener errores tontos, podría usar TagBuilder, etc. Podría modificarse fácilmente para reutilizar la clase Wrapper para diferentes ... envoltorios (incluso puede ya sea uno genérico en ASP.NET MVC - no he tenido necesidad de uno).

public static class WrapHelper 
{ 
    private class Wrapper : IDisposable 
    { 
     private bool disposed; 
     private readonly TextWriter writer; 

     public Wrapper(HtmlHelper html) 
     { 
      this.writer = html.ViewContext.Writer; 
     } 

     public void Dispose() 
     { 
      if (disposed) return; 

      disposed = true; 

      writer.WriteLine(" </div>"); 
      writer.WriteLine("</div>"); 
     } 
    } 

    public static IDisposable Wrap(this HtmlHelper html, string title) 
    { 
     TextWriter writer = html.ViewContext.Writer; 

     writer.WriteLine("<div class=\"module\">"); 
     writer.WriteLine(" <h3>" + html.Encode(title) + "</h3>"); 
     writer.WriteLine(" <div>"); 

     return new Wrapper(html); 
    } 
} 

Uso:

@using (Html.Wrap("Title")) 
{ 
    <p>My very own markup.</p> 
} 
+0

Esto es exactamente lo que estaba buscando. – Josh

+0

Hay un ejemplo más simple en http://stackoverflow.com/questions/7196276/creating-mvc3-razor-helper-like-helper-beginform –

+0

Me es difícil ver lo que lo hace más simple, considerando que la solución es exactamente la lo mismo ... El único código adicional en este ejemplo está allí para cumplir con los requisitos de la pregunta, y un control rudimentario para evitar que los efectos secundarios de Dispose se llamen dos veces. – JimmiTh

0

Si está utilizando la maquinilla de afeitar y MVC 3 es muy fácil de escribir un método de ayuda rápida que iría dentro de la carpeta App_Code, (voy a NÓMBRELO MyHtmlHelpers)

me gustaría probar algo un poco diferente y un poco más fácil, tales como:

@helper myTemplate(string title, string markup){ 
    <div class="module"> 
     <h3>@title</h3> 
     @markup 
    </div> 
} 

y la manera de U desde un archivo .cshtml es el siguiente:

@MyHtmlHelpers.myTemplate('title','markup') 

Debería funcionar, si lo entiendo correctamente.

+1

No quiero que el marcado sea un parámetro de cadena, porque quiero tener el marcado como html normal en mi opinión. Lo que estoy buscando hacer es imitar con un ayudante en MVC 3 cómo en MVC 2 podrías tener '<% usando (Html.Beginform()) {%> HTML markup <% } %>' – Josh

3

@TheKaneda, gracias por la información. Tomé su idea y la extendí, de modo que proporciona un nombre ParcialView y sabe cómo analizarlo.

<Extension()> _ 
Public Function UseTemplate(ByVal html As HtmlHelper, ByVal PartialView As String) As IDisposable 
    Return New TemplateWrapper(html, PartialView) 
End Function 

Public Class TemplateWrapper 
    Implements IDisposable 

    Private _HtmlHelper As HtmlHelper 

    'Index 0 is header 
    'Index 1 is footer 
    Private _TemplateWrapper As String() 

    Public Sub New(ByVal Html As HtmlHelper, ByVal PartialView As String) 

     _TemplateWrapper = Html.Partial(PartialView).ToHtmlString.Split("@@RenderBody()") 

     _HtmlHelper = Html 
     _HtmlHelper.ViewContext.Writer.Write(_TemplateWrapper(0)) 

    End Sub 

    Public Sub Dispose() Implements IDisposable.Dispose 

     _HtmlHelper.ViewContext.Writer.Write(_TemplateWrapper(1).Substring(12)) 

    End Sub 

End Class 

Use el mismo uso que @ TheKaneda's example. En su vista parcial, en lugar de llamar @RenderBody(), simplemente ponga @@ RenderBody() que actúa como una bandera para la parte media de su contenido. Perdón por la traducción de VB.

Utiliza un ejemplo de mi uso.

Using Html.UseTemplate("ContentWrapper") 

    @Html.EditorFor(Function(m) m.Var1, "TemplateHint") 
    @Html.EditorFor(Function(m) m.Var2, "TemplateHint") 
    @Html.EditorFor(Function(m) m.Var3) 

End Using 

My Partial se parece así ...

<div class="content"> 
    @@RenderBody() 
</div> 
15

También existe la otra forma, sin trucos desechables, que también requiere un poco menos de trabajo, ideal para pequeños ayudantes.

@helper MyHelper(string title, Func<object, object> markup) { 
    <div class="module"> 
     <h3>Title</h3> 
     <div> 
      <p>@markup.DynamicInvoke(this.ViewContext)</p> 
     </div> 
    </div> 
} 

El uso de esta ayuda se ve así:

@MyHelper("This is my Title", 
    @<p>Here is my custom markup</p> 
) 

o con múltiples líneas:

@MyHelper("This is my Title", 
    @<text> 
     <p>More than one line</p> 
     <p>Of markup</p> 
    </text> 
) 

controles Telerik MVC utilizan este truco, por ejemplo, para permitir añadir el código JavaScript en la carga del documento.

Aquí también hay un bonito example. También hay información here.

+0

Me gusta este ejemplo. Parece ser mucho más fácil de implementar. ¿Puedes ayudarme a resolver un problema? this.ViewContext no se compila porque el método MyHelper es estático (al menos como lo he configurado en mi helper). –

+1

Sorprendentemente, tiende a funcionar también si lo pasa nulo, pero tal vez podría haber algún escenario complejo que se bloquee. De todos modos, debería poder obtener acceso a ViewContext a través del objeto Htmlhelper (si su método estático es el método de extensión html, debería tener acceso a él) usando la propiedad ViewContext. Si no es el caso, puede pasar ViewContext al método manualmente. – slawek

+0

Gracias por la respuesta. Pasar nulo funcionó. Creo que la razón por la que mi código no tuvo acceso a ViewContext es porque estoy construyendo un sitio MVC en lugar de la aplicación. Está trabajando ahora. Creo que tu respuesta es la mejor porque es simple y funciona. –

Cuestiones relacionadas