Los Helpers de HTML en MVC nos facilitan la creación de vistas al encapsular la creación del código de marcado. Desarrollar un Helper que cree un label o un input, es un caso trivial, pero podemos encontrarnos con que necesitemos utilizar la sintaxis de Razor para generar contenido entre la etiqueta de apertura y cierre, por ejemplo llamar a vistas parciales u obtener el resultado de pintar un Action
Como hemos comentado, generar un Helper para un input o un label es una tarea sencilla, con un método de extensión podemos resolver nuestro requerimiento:
public static MvcHtmlString MiLabel(this HtmlHelper htmlHelper, String NombreCampo, String Caption)
{
String formatresult = "<label for='{0}'>{1}</label>";
return new MvcHtmlString(String.Format(formatresult, NombreCampo, Caption));
}
Una llamada a este helper:
@MiLabel("NombreCampo", "Valor")
Nos generaría en el marcado resultante:
<label for="NombreCampo">Valor</label>
El asunto se complica si necesitamos marcado entre las etiquetas de apertura y cierre. Un enfoque para solucionar esto sería escribir los métodos correspondientes al inicio y al fin de la etiqueta, y llamarlos de la misma forma que en el ejemplo anterior.
PERO, somos personas curiosas y elegantes, por lo que decidimos que lo queremos hacer bien, de forma concisa. Nuestra curiosidad nos lleva a observar que todas las vistas de creación y edición que nos genera Visual Studio hay un elegante using que rodea entre llaves todo el marcado de los campos del formulario.
@using (Html.BeginForm("Accion", "Controlador", FormMethod.Post)) {
{
<h3>Titulo</h3>
}
¡Un momento! ¿ using ? ¿ No se utiliza la clausula using para crear un objeto que implementa la interfaz IDisposable, ejecutar código y destruirlo de forma ordenada ?
Efectivamente esa es la forma con la que podremos crear nuestros helpers, sólo necesitaremos:
- Una clase que implemente la interfaz
IDisposabley - un método que nos devuelva un objeto de esta clase
En resumidas cuentas, utilizaremos el método para crear un objeto y general el HTML del inicio del elemento, y el método Dispose del objeto creado para cerrarlo
Sin más dilación, vamos a ver un ejemplo de esta técnica
Creamos un método de extensión que devuelva una instancia de la clase que creemos después:
public static MvcContainer BeginContainer(this HtmlHelper htmlHelper, String tagname)
{
return new MvcContainer(htmlHelper.ViewContext.Writer, tagname);
}
Y veamos la definición de la clase MvcContainer generada en el paso anterior:
public class MvcContainer : IDisposable
{
private bool disposed;
private readonly TextWriter _writer;
private string _tagname;
public string tagname
{
get { return _tagname; }
set
{
_tagname = value;
_writer.Write(String.Format("<{0}>", _tagname));
}
}
public MvcContainer(TextWriter writer)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
this._writer = writer;
}
public MvcContainer(TextWriter writer, String tagname) : this(writer)
{
this.tagname = tagname;
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
this.disposed = true;
_writer.Write(String.Format("</{0}>", _tagname));
}
}
[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
public void Dispose()
{
Dispose(true /* disposing */);
GC.SuppressFinalize(this);
}
public void EndContainer()
{
Dispose(true);
}
}
Sólo tenemos que fijarnos en el método Dispose requerido por la interfaz IDisposable en el que escribimos en la salida el elemento de cierre
Utilizamos el writer de la respuesta del contexto, ya que si escribimos con el método Response.Write, el marcado a generar nos aparecerá al principio del resultado, y no en la posición del template Razor utilizado.
Si llamamos al método de extensión creado anteriormente:
@using (Html.BeginContainer("p"))
{
<text>Contenido del párrafo</text>
}
Obtendremos la salida deseada:
<p>Contenido del párrafo</p>
1 comentario:
Que grande eres!
Publicar un comentario