Webforms: Forzar postbacks

Jejejee… Sí, aunque no lo parezca a veces hago temillas con Webforms, y es que uno tiene que conocer al enemigo! 😛

Lo que voy a comentar hoy, es como forzar un postback desde un control propio. Una búsqueda en google da varios resultados, pongo un par de ejemplo:

  1. http://tratadooscuro.blogspot.com.es/2009/02/dopostback-ese-gran-desconocido.html
  2. http://programacion.porexpertos.es/provocar-un-postback-desde-javascript-con-aspnet/

Ambos ejemplos dicen lo mismo pero lo cierto es que, en mi opinión, hay una manera ligeramente mejor que hacerlo, pero parece que se desconoce bastante porque buscando en google aparecen menos resultados.

Bueno, si miráis los dos enlaces que he puesto arriba, forzar un postback desde un control propio es tan simple como llamar a __doPostback. Este método lo añade automáticamente Webforms cuando lo necesita.

Si seguimos las instrucciones de cualquiera de los dos enlaces anteriores, si queremos generar un control que sea p.ej. un enlace que al pulsarlo genere un postback vemos que debemos usar un código como este:

[DefaultProperty(«Text»)]

[ToolboxData(«<{0}:MyControl runat=server></{0}:MyControl>»)]

public class MyControl : WebControl

{

    [Bindable(true)]

    [Category(«Appearance»)]

    [DefaultValue(«»)]

    [Localizable(true)]

    public string Text

    {

        get

        {

            String s = (String)ViewState[«Text»];

            return s ?? string.Empty;

        }

 

        set

        {

            ViewState[«Text»] = value;

        }

    }

 

    protected override void RenderContents(HtmlTextWriter output)

    {

        output.AddAttribute(HtmlTextWriterAttribute.Href,

            «javascript:__doPostBack(»,»);»);

        output.RenderBeginTag(HtmlTextWriterTag.A);

        output.Write(Text);

        output.RenderEndTag();

    }

}

Si creamos una Webform vacío y añadimos el control y probamos la página, efectivamente se renderiza el tag <a> que incluye la llamada a __doPostBack. Pero fijaos que este es el código HTML generado por el Webform:

<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Transitional//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd»>

 

<html xmlns=»http://www.w3.org/1999/xhtml» >

<head><title>

 

</title></head>

<body>

    <form name=»form1″ method=»post» action=»default.aspx» id=»form1″>

<div>

<input type=»hidden» name=»__VIEWSTATE» id=»__VIEWSTATE» value=»/wEPDwUKLTk1OTYxMjkxMmRkGui/AV2Pv2fTTQJWmL8w2grZiZY=» />

</div>

 

    <div>

 

        <span id=»MyControl1″><a href=»javascript:__doPostBack(»,»);»>Demo</a></span>

 

    </div>

    </form>

</body>

</html>

¿Alguien ve el método __doPostBack? No, ¿verdad? Eso es porque Webforms no lo ha generado, y no lo ha generado porque no sabe que alguien va a usarlo. La verdad es que Webforms solo genera este método cuando sabe que algún control lo requiere. En páginas medio complejas la probabilidad de que algún control requiera postback es tan grande que por eso mucha gente cree que siempre se genera. Pero no es así.

Poner código “a saco” para llamar a __doPostBack funciona en la mayoría de casos pero no es una buena práctica porque estamos usando una característica interna de Webforms. Si en la siguiente release de Webforms Microsoft decide renombrar esta función todo nuestro código se viene abajo.

Vale… entonces si no podemos llamara a __doPostBack a saco, que debemos hacer? Pues usar el método GetPostBackClientHyperlink de la clase ClientScriptManager. Para obtener una instancia de ClientScriptManager se puede usar la propiedad ClientScript del objeto Page:

protected override void RenderContents(HtmlTextWriter output)

{

    output.AddAttribute(HtmlTextWriterAttribute.Href,

        this.Page.ClientScript.GetPostBackClientHyperlink(this, «»));

    output.RenderBeginTag(HtmlTextWriterTag.A);

    output.Write(Text);

    output.RenderEndTag();

}

¡Listos! Ahora si ejecutamos de nuevo el Webform, vemos que el código generado es:

<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Transitional//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd»>

 

<html xmlns=»http://www.w3.org/1999/xhtml» >

<head><title>

 

</title></head>

<body>

    <form name=»form1″ method=»post» action=»default.aspx» id=»form1″>

<div>

<input type=»hidden» name=»__VIEWSTATE» id=»__VIEWSTATE» value=»/wEPDwUKLTk1OTYxMjkxMmRkGui/AV2Pv2fTTQJWmL8w2grZiZY=» />

</div>

 

<div>

 

    <input type=»hidden» name=»__EVENTTARGET» id=»__EVENTTARGET» value=»» />

    <input type=»hidden» name=»__EVENTARGUMENT» id=»__EVENTARGUMENT» value=»» />

</div>

    <div>

 

        <span id=»MyControl1″><a href=»javascript:__doPostBack(‘MyControl1’,»)»>Demo</a></span>

 

    </div>

 

<script type=»text/javascript»>

//<![CDATA[

var theForm = document.forms[‘form1’];

if (!theForm) {

    theForm = document.form1;

}

function __doPostBack(eventTarget, eventArgument) {

    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {

        theForm.__EVENTTARGET.value = eventTarget;

        theForm.__EVENTARGUMENT.value = eventArgument;

        theForm.submit();

    }

}

//]]>

</script>

 

</form>

</body>

</html>

Por un lado ahora Webforms nos ha generado el __doPostBack y por otro como podemos ver el el atributo href de nuestro enlace tenemos la llamada a doPostBack correcta (por norma general el primer parámetro es el ID del control que realiza la llamada).

Y ya que sabemos generar PostBacks… ¿como recibirlos?

Hemos visto como generar un PostBack desde nuestro control, ahora… como podemos decirle a Webforms que nuestro control quiere enterarse de los postbacks que él haya efecutado?

Pues para esto basta con implementar la interfaz IPostBackEventHandler que tiene un solo método:

public interface IPostBackEventHandler

{

    void RaisePostBackEvent(string eventArgument);

}

Esta interfaz nos permite hacer algo cuando hay un postback generado por el propio control. Por norma general lo que se hace es lanzar un evento de .NET (p.ej. Click). Vamos a ver un ejemplo muy rápido. Para ello añadimos un evento Click a nuestro control:

public event EventHandler Click;

protected virtual void OnClicked()

{

    var handler = Click;

    if (handler != null) handler(this, EventArgs.Empty);

}

Ahora implementamos la interfaz IPostBackEventHandler y el método RaisePostBackEvent:

public void RaisePostBackEvent(string eventArgument)

{

    OnClicked();

}

Cuando ahora se pulse nuestro enlace se generará un evento Click que podemos capturar desde el Webform, como cualquier otro evento.

Además fijaos que RaisePostBackEvent recibe una cadena (eventArgument). El valor de esta cadena es el valor del segundo parámetro de GetClientPostBackHyperlink que hemos usado para generar la llamada a __doPostBack. De esta manera podemos crear controles que lancen varios eventos en función del valor de eventArgument.

Un saludo!

Un comentario sobre “Webforms: Forzar postbacks”

  1. Interesante…. la verdad es que pocas veces he tenido necesidad de hacer cosas similares, aunque por el contrario si que me parece que es complicado hacer un autopostback de un combo en ASP.Net MVC xD

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *