2011-04-13 8 views
6

tengo actualmente un recipiente div para todos los campos de entrada en mi forma, similar a:Razor tipo base/con plantilla Delegados de afeitar con el "uso de" palabras clave

<div class="ux-single-field ui-widget-content ui-corner-all"> 
    @Html.LabelFor(m => m.Name) 
    @Html.TextBoxFor(m => m.Name) 
</div> 

Me gustaría saber cómo podría yo encapsular esta usando un templated razor delegate (o any other trick), por lo que al igual que nosotros usamos:

@using (Html.BeginForm()) { 
} 

yo podría simplemente envolver mis elementos como:

@using (Html.ContentField()) { 
    @Html.LabelFor(m => m.Name) 
    @Html.TextBoxFor(m => m.Name) 
} 
+0

Puedo preguntarle lo que está tratando de lograr? - ¿Desea que Html.ContentField() genere un div? – ebb

+0

@ebb Sí. El div anterior – rebelliard

Respuesta

7

usando la navaja Vista del motor, esto es lo que funciona:

namespace MyProject.Web.Helpers.Extensions 
{ 
    public static class LayoutExtensions 
    { 
     public static ContentField BeginContentField(this HtmlHelper htmlHelper) 
     { 
      return FormHelper(htmlHelper, new RouteValueDictionary()); 
     } 

     public static ContentField BeginContentField(this HtmlHelper htmlHelper, RouteValueDictionary htmlAttributes) 
     { 
      return FormHelper(htmlHelper, htmlAttributes); 
     } 

     public static void EndContentField(this HtmlHelper htmlHelper) 
     { 
      htmlHelper.ViewContext.Writer.Write("</div>"); 
     } 

     private static ContentField FormHelper(this HtmlHelper htmlHelper, IDictionary<string, object> htmlAttributes) 
     { 
      TagBuilder tagBuilder = new TagBuilder("div"); 
      tagBuilder.MergeAttributes(htmlAttributes); 
      tagBuilder.MergeAttribute("class", "ux-single-field ui-widget-content ui-corner-all"); 

      htmlHelper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag)); 
      return new ContentField(htmlHelper.ViewContext.Writer); 
     } 
    } 

    public class ContentField : IDisposable 
    { 
     private bool _disposed; 
     private readonly TextWriter _writer; 

     public ContentField(TextWriter writer) 
     { 
      if (writer == null) 
       throw new ArgumentNullException("writer"); 

      _writer = writer; 
     } 

     [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")] 
     public void Dispose() 
     { 
      Dispose(true /* disposing */); 
      GC.SuppressFinalize(this); 
     } 

     protected virtual void Dispose(bool disposing) 
     { 
      if (!_disposed) 
      { 
       _disposed = true; 

       _writer.Write("</div>"); 
      } 
     } 

     public void EndForm() 
     { 
      Dispose(true); 
     } 
    } 
} 

FYI: Usando el viejo motor ASPX, here's how to do it.

1

Echemos un vistazo (o adivine) qué hace Html.BeginForm(). Desde el "punto de vista del renderizado", en general solo renderiza la etiqueta de inicio de formulario en la salida html. es desechable porque en este caso sabe cuándo el contenido html interno para el formulario ha terminado de renderizarse y puede representar la etiqueta final </form> en su método Dispose(). Con todo esto, obtienes: primero, se muestra la etiqueta form abierta, que el contenido html personalizado que deseas, y luego viene la etiqueta final. Resultado: obtiene el formulario html completo en la salida.

<form> 

...contents(Result of Html.TextBoxFor, etc. helpers) 

</form> 

Creo que su situación sería mejor resuelta como si fuera un formulario. Por el momento no tengo mucho tiempo para escribir el código completo, pero si echas un vistazo a FormExtensions.BeginForm observando el código fuente (Gracias @druttka) reflector (si tienes una versión anterior o una licencia comprada) o http://wiki.sharpdevelop.net/ilspy.ashx y las explicaciones anteriores, puede obtener el gran punto desde donde comenzar. Elimine el código innecesario del método BeginForm, cree su MvcContentField: clase IDisposable en lugar de MvcForm, cambie el Dispose() en él para representar la etiqueta div final y obtendrá exactamente lo que necesita.

+2

No hay necesidad de Reflector o ILSpy; la fuente MVC3 está disponible de forma gratuita http://aspnet.codeplex.com/releases/view/58781 Verifique los archivos MvcForm.cs y FormExtensions.cs en la carpeta/espacio de nombres Html. –

+0

Hmmkay. Lo investigaré e intentaré resolverlo. Te mantendré informado. – rebelliard

+0

@druttka Me olvidé de eso con prisa. Gracias :) – archil

2

La respuesta aceptada fue muy útil. Lo cambié y lo actualicé un poco para mi proyecto, y creo que esta versión será un poco más clara para las personas que solo quieren saltar y hacer cosas.

Los cambios incluyen:

  • pasaron a utilizar los tipos anónimos en lugar de IDictionary, ya que parece ser la norma ahora.
  • Se eliminó la sintaxis Begin/End ..., ya que solo usaré esto con la sintaxis using() y, a tal fin, creo que esto es más claro.
  • Nombres retocados para mayor claridad.
  • Agregué un argumento headerText, que mi panel usa para crear un encabezado div separado. Esto se elimina fácilmente si no lo necesita/lo quiere.
  • Reformé algunos métodos.
  • Si está buscando un panel de ayuda para KendoUI, bueno, eso es lo que es. Tengo una clase llamada panel a la que hace referencia, y que solo agrega margen y ancho a las etiquetas KendoUI.

    usando Sistema; usando System.Diagnostics.CodeAnalysis; usando System.IO; usando System.Web.Mvc;

    MyProject.Web.HtmlHelpers.Extensions de espacio de nombres { LayoutExtensions clase public static { Panel StyledPanel estáticos públicos (esto HtmlHelper HtmlHelper, objeto htmlAttributes = null, cuerda headerText = null) { retorno GetStyledPanel (HtmlHelper, headerText , htmlAttributes); }

    private static StyledPanel GetStyledPanel(this HtmlHelper htmlHelper, string headerText, object htmlAttributes) 
        { 
    
         if (!string.IsNullOrWhiteSpace(headerText)) 
          RenderHeading(htmlHelper, headerText); 
    
         RenderDiv(htmlHelper, htmlAttributes); 
    
         return new StyledPanel(htmlHelper.ViewContext.Writer); 
        } 
    
        private static void RenderHeading(HtmlHelper htmlHelper, string headerText) 
        { 
         TagBuilder tagBuilder = new TagBuilder("div"); 
         tagBuilder.Attributes.Add("class", "panelHead"); 
         tagBuilder.SetInnerText(headerText); 
    
         htmlHelper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.Normal)); 
        } 
    
        private static void RenderDiv(HtmlHelper htmlHelper, object htmlAttributes) 
        { 
         TagBuilder Tag = new TagBuilder("div"); 
         Tag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); 
         Tag.MergeAttribute("class", "panel k-block k-shadow"); 
    
         htmlHelper.ViewContext.Writer.Write(Tag.ToString(TagRenderMode.StartTag));   
        } 
    
    } 
    
    public class StyledPanel : IDisposable 
    { 
        private bool m_Disposed; 
        private readonly TextWriter m_Writer; 
    
        public StyledPanel(TextWriter writer) 
        { 
         if (writer == null) 
          throw new ArgumentNullException("Writer was null. This should never happen."); 
    
         m_Writer = writer; 
        } 
    
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")] 
        public void Dispose() 
        { 
         Dispose(true); 
         GC.SuppressFinalize(this); 
        } 
    
        protected virtual void Dispose(bool disposing) 
        { 
         if (!m_Disposed) 
         { 
          m_Disposed = true; 
          m_Writer.Write("</div>"); 
         } 
        } 
    
        public void EndForm() 
        { 
         Dispose(true); 
        } 
    } 
    

    }

uso podría ser así:

@using (Html.Panel(headerText: "My Header", 
        htmlAttributes: new { style = "width: 800px;" })) 
{ 
    <table> 
      <tr> 
       <td class="label">First Name:</td> 
       <td class="content"><input name="thing" class="k-textbox" /></td> 

       <td class="label">Last Name:</td> 
       <td class="content"><input name="thing" class="k-textbox" /></td> 
      </tr> 
    </table> 
} 

O simplemente:

@using (Html.Panel()) 
{ 
    <table> 
      <tr> 
       <td class="label">First Name:</td> 
       <td class="content"><input name="thing" class="k-textbox" /></td> 

       <td class="label">Last Name:</td> 
       <td class="content"><input name="thing" class="k-textbox" /></td> 
      </tr> 
    </table> 
} 
Cuestiones relacionadas