Вы находитесь на странице: 1из 8

Definir y producir eventos en una clase

Una vez que tenemos unas nociones de que son los eventos y qu relacin tienen con los delegados, es hora de que veamos de forma prctica cmo definirlos en nuestras clases y qu es lo que tenemos que hacer para que una aplicacin lo intercepte, sin olvidarnos de cmo y cundo lo podemos producir. Tambin nos ocuparemos de ver cmo eliminar un mtodo de la lista de mtodos que deben ser notificados por el evento.

Definir eventos en una clase


Para definir un evento en una clase, lo primero que debemos hacer es definir un delegado con la "firma" que tendr el mtodo utilizado para interceptar el evento. Ese delegado debe estar definido con un mbito adecuado para que puede ser utilizado por los clientes que los vayan a utilizar. Teniendo en cuenta que en el fondo un delegado es una clase, el delegado (o los delegados) deben estar declarados en el mismo nivel que nuestra clase, de esa forma nos aseguramos que est accesible. Una vez definido el delegado, tenemos que definir el evento en nuestra clase. La forma definirlo es usando la instruccin event seguida del nombre del delegado y a continuacin el nombre que queramos darle. Para este ejemplo, vamos a usar una clase llamada Empleado, que tendr dos propiedades de lectura/escritura: Nombre y Apellidos, una propiedad de solo lectura: Salario, (el valor de esta propiedad lo indicaremos en el constructor de la clase), un mtodo que reemplaza al mtodo ToString de la clase object, el cual utilizaremos para mostrar los datos de la clase; adems, tendremos un evento llamado DatosModificados, el cual se producir cada vez que se modifique, (realmente cuando se asigne), las dos propiedades que tienen acceso de escritura. Este evento no tendr ningn parmetro. Empecemos declarando el delegado, que como hemos dicho no tendr ningn parmetro, y al utilizarse para recibir eventos, ser de tipo void.
public delegate void DatosCambiadosEventHandler();

Nota: Segn las recomendaciones de nomenclatura de .NET Framework, los nombres de los delegados deben terminar con EventHandler.

El evento lo declararemos de la siguiente forma:


public event DatosCambiadosEventHandler DatosCambiados;

Producir un evento en nuestra clase


Para producir un evento en nuestra clase, y de esta forma notificar a quin quiera interceptarlo, utilizaremos el nombre con el que hemos declarado el evento, pero debemos recordar lo que comentamos anteriormente: tenemos que comprobar si algn mtodo ser notificado, es decir, si se ha aadido a ese evento una direccin de memoria gestionada por el delegado. En caso de que no lo hagamos, (y no haya ningn mtodo esperando ser notificado), recibiremos una excepcin del tipo NullReferenceException, y como podemos comprobar en la figura 2.17, el IDE de Visual Studio 2005 nos indica lo que debemos hacer:

Figura 2.17. Error al producir un evento que no est interceptado

Nota: De forma interna y totalmente transparente para nosotros, el compilador de C# crea un objeto, (el cual inicialmente tiene un valor nulo), que ser el encargado de gestionar los clientes que interceptan los eventos. Para lograrlo, define dos mtodos pblicos llamados add_NombreDelEvento y remove_NombreDelEvento que son los que se utilizan cuando aadimos nuevos mtodos a la lista de mtodos a notificar y cuando los quitamos de dicha lista.

Para que no se produzca ese error, lo que debemos hacer es comprobar si el "evento" contiene un valor nulo, y en caso de que no lo tenga lanzamos el evento:
if (DatosCambiados != null) DatosCambiados();

Nota: Segn las recomendaciones de .NET Framework sobre los eventos, para lanzar un evento en una clase deberamos declarar un mtodo protegido llamado OnNombreDelEvento, al que llamaremos cuando tengamos que lanzarlo. Y si alguna clase se deriva de la nuestra y sobrescribe dicho mtodo para adaptarlo a sus necesidades, debera llamar a ese mtodo de la clase base para que los delegados que existan sigan notificando dicho evento.

Asociar los eventos de una clase con un mtodo


Tal como hemos estado comentando, la forma que tiene C# de asociar eventos con los mtodos que lo interceptarn es usando el operador += para asignar al evento el delegado, el cual, como ya sabemos recibe un parmetro que es el mtodo que recibir la notificacin de que dicho evento se ha producido. En la aplicacin de ejemplo, declaramos una variable del tipo Empleado y llamamos al constructor en el que le indicamos los datos que debe asignar a cada una de las propiedades:
Empleado emp; emp = new Empleado("pepe", "Ruiz", 100);

Antes de asociar el evento con un mtodo, debemos declararlo con la misma firma que ha definido el delegado:
static void emp_DatosCambiados() { Console.WriteLine("Datos cambiados en el Empleado"); }

En este caso, es un mtodo de tipo void que no recibe ningn argumento. Por ltimo tendremos que "ligar" el evento con el mtodo, esto lo hacemos de la siguiente forma:

emp.DatosCambiados += new DatosCambiadosEventHandler(emp_DatosCambiados);

Si ejecutamos el siguiente cdigo:


Console.WriteLine(emp.ToString()); emp.Nombre = "Jose"; Console.WriteLine(emp.ToString());

Obtendremos la siguiente salida en la consola: Ruiz, pepe Datos cambiados en el Empleado Ruiz, Jose Ya que al asignarle un valor a la propiedad es cuando se lanza el evento.

Veamos el cdigo completo de la clase Empleado, para ver cundo lanzamos los eventos:
public class Empleado { private string nombre; private string apellidos; private decimal salario;

public event DatosCambiadosEventHandler DatosCambiados;

public Empleado(string nombre, string apellidos, decimal salario) { this.nombre = nombre; this.apellidos = apellidos; this.salario = salario; }

public string Nombre {

get{ return nombre; } set { nombre = value; if (DatosCambiados != null) DatosCambiados(); } }

public string Apellidos { get{ return apellidos; } set { apellidos = value; if (DatosCambiados != null) DatosCambiados(); } }

public decimal Salario { get{ return salario; } }

public override string ToString() { return Apellidos + ", " + Nombre; } }

Desasociar eventos
Cuando no queramos que un evento sea interceptado, podemos eliminar el delegado que previamente hemos asociado. Esto lo haremos de la misma forma que cuando asociamos un mtodo a un evento, pero en lugar de utilizar el operador +=, tendremos que usar el operador -=. En el siguiente cdigo "desligamos" el mtodo del evento, de forma que a partir de esa asignacin, dejar de recibir notificaciones:
emp.DatosCambiados -= new DatosCambiadosEventHandler(emp_DatosCambiados);

Por tanto, si despus de esa lnea aadimos este cdigo:


Console.WriteLine(emp.ToString()); emp.Nombre = "Antonio"; Console.WriteLine(emp.ToString());

No se mostrar la lnea que indica que los datos del empleado han cambiado.

Detectar cundo se aade o se elimina un delegado de un evento


Si queremos detectar cundo se aade un delegado a un evento o cundo se elimina, podemos utilizar una de las nuevas caractersticas de Visual C# 2005: propiedades de eventos o eventos de propiedades. La forma de hacerlo es algo ms complicado que lo que hemos visto, pero realmente no es tan distinto. Esta caracterstica la podemos usar cuando de alguna forma nos interese tener una relacin de los mtodos que interceptan nuestros eventos o bien para solventar ciertos conflictos que se pueden presentar cuando una clase implementa ms de una interfaz en las que se ha definido un evento que tiene el mismo nombre en las interfaces, y el delegado usado en cada uno de ellos sea diferente.

Si aplicamos esta nueva forma de definir un evento en nuestra clase Empleado, debemos eliminar la declaracin que tenamos del evento y utilizar esta otra:
// La variable privada ser la que se usar // en esta clase para lanzar los eventos. private DatosCambiadosEventHandler datosCambiados;

// El evento declarado al estilo de una propiedad. public event DatosCambiadosEventHandler DatosCambiados { add { datosCambiados += value; Console.WriteLine("El mtodo a notificar es: {0}", value.Method.Name); Console.WriteLine("Se aade un delegado al evento DatosCambiados"); } remove { datosCambiados -= value; Console.WriteLine("Se elimina un delegado al evento DatosCambiados"); } }

Lo primero que hacemos es declarar una variable privada del mismo tipo que el delegado, esa variable ser la que se use, como solemos hacer con cualquier propiedad, para almacenar "el valor interno de la propiedad", aunque en este caso sea una propiedad "especial". Despus declaramos el evento-propiedad, que como vemos se hace de la misma forma que cuando declaramos un evento, con la diferencia de que en lugar de terminarlo con un punto y coma, utilizamos un bloque de cdigo, en el que definimos otros dos bloques, pero en lugar de utilizar los tpicos get y set de las propiedades normales, aadiremos un bloque para cuando se aada el delegado (add) y otro para cuando se elimine (remove). Esos dos bloque reciben un parmetro implcito (value), el cual representa al delegado que se quiere aadir o quitar, por tanto debemos realizar esas mismas operaciones dentro de cada bloque, utilizando los operadores += y -=. Como podemos comprobar en el listado anterior, tambin podemos aadir ms cdigo a cada bloque, incluso podemos obtener informacin del delegado usado para asociar el evento con un mtodo. Para producir este evento, en lugar de usar el declarado como propiedad, tendremos que usar la variable privada, el uso es exactamente el mismo que vimos anteriormente:
nombre = value; if (datosCambiados != null)

datosCambiados();

Aunque parezca que es el mismo cdigo de antes, debemos recordar que C# hace distincin entre maysculas y minsculas. En el programa que utiliza la clase Empleado no tenemos que hacer ningn cambio, ya que la forma que implementemos nuestro evento no afecta fuera de la clase.

Вам также может понравиться