miércoles, 10 de febrero de 2010

Eventos y delegados en C#. Error de delegado = null.

En este post hice un ejemplo de cómo crear un evento en un botón de un formulario y suscribirlo desde otro. Es decir, pulso el botón en el formulario B y pasa algo en el formulario A.
Pero lo mezcle con el uso del patron singleton y se me había escapado un insidioso error que me ha llevado, una vez más, un par  horitas hasta encontrar el problema.
Recapitulemos:
“ Tenemos un formulario A en donde tenemos un método llamado hazAlgo()"
” Tenemos un control de usuario llamado donde tenemos un botón ACEPTAR”
” Cuando pulsamos el botón ACEPTAR se debe lanzar el método hazAlgo()”
1º Insertamos el control de usuario en el formulario A (no te voy a explicar como se hace, búscalo en San Google) y le vamos a llamar cuAlerta.
2º En el control de usuario declaramos el Delegado en el ámbito del namespace. Es decir por encima de las clase del control de usuario. Es decir, lo más sencillo es ponerlo justo debajo de la última declaración del using.
Esto es debido a que el delegado debe ser visible continuadamente, y no estar dentro de la construcción/destrucción de la clase.
public delegate void bAceptarClickHandler();
3º Declaramos el evento justo después del inicio de la declaración de la clase y antes del primer método.
public event bAceptarClickHandler bAceptar_Click;


4º Declaramos un método virtual que va a lanzar el evento. No tengo claro si este punto se puede enlazar con el siguiente, pero supongo que sí. Yo prefiero tenerlo separado para un mayor control.


protected virtual void OnAceptarClick()
{
if (bAceptar_Click != null)
{ bAceptar_Click(); }
}


5º Dentro del evento del botón ACEPTAR invocamos al método virtual que lanza el evento.


public void bAceptar_Click(object sender, EventArgs e)
{
OnAceptarClick();
}


6º Nos vamos al formulario A y suscribimos al método hazAlgo() con el evento bAceptar_Click().

Esta suscripción hay que hacerla fuera del !IsPostBack para que en cada ciclo de destrucción/construcción de la página (acuerdate que en ASP.NET no se mantiene el estado, por lo cual se tiene que recargar cada vez todo) se vuelva a suscribir al evento del control de usuario.


protected void Page_Load(object sender, EventArgs e)
{
cuAlerta.bAceptar_Click += hazAlgo;

if (!IsPostBack)
{
…
}
}

Y si sigues estás 6 reglas te funcionará como la seda.

2 comentarios:

Anónimo dijo...

Hola,
solo una consulta, porque en el Page_Load declaras lo siguiente:
cuAlerta.bAceptar_Click += aceptarAlerta;
A que hace referencia "aceptarAlerta", no deberia estar ahi el EventHandler que quieres ejecutar?.
Te agradecere la respuesta.
Saludos

Juan Quijano dijo...

Ha sido el efecto del uso del antipatron copy&paste :)

En vez de invocar al método aceptarAlerta, lo he modificado para que invoque corréctamente al método hazAlgo().

Este método debiera de estar en cualquier punto de la clase y es en donde se inserta el código que se desea lanzar cuando la suscripción reciba la ejecución del evento.

Es decir, cuando pulses el botón, qué método debe lanzar.