sábado, 18 de noviembre de 2017

Curso de C#: eventos

Para disparar un evento en C# se utilizan los delegados


Un evento es la forma que tiene una clase para notificar a los clientes de la clase que ha ocurrido  algo digno de capturar en un método en el que se inserta código para tratarlo. Su utilización más habitual se produce en las interfaces gráficas; es de todos conocido el evento click que se ejecuta al pulsar un botón de una interfaz gráfica.

Los eventos proporcionan un medio adecuado para que los objetos puedan reaccionar a cambios de estado que pueden resultar útiles para los clientes del objeto.

Los eventos se declaran mediante delegados.


Eventos en C#



En primer lugar, creamos un delegado que manejará los eventos de cambio en al introducir objetos en una lista.

public delegate void ManejadorEventosCambio(object sender, EventArgs e);

En el programa principal Main(), creamos un objeto de una clase Lista que es la que contiene el evento
public static void Main()
        {
            // Crea una nueva lista.
            EventoCambiaLista lista = new EventoCambiaLista();

Después se crea un objeto que escucha los eventos de cambio de la lista.

            EscuchaEvento escuchador = new EscuchaEvento(lista);

EscuchaEvento es un método que pasa por referencia un objeto lista de la clase EventoCambiaLista. Este método lo añade al delegado de la siguiente forma:
Lista.Cambio += new ManejadorEventosCambio(ListaCambio);

La definición del método completo es la siguiente:
public EscuchaEvento(EventoCambiaLista lista)
        {
            Lista = lista;

            //Se añade "ListaCambio" al evento Cambio de Lista.
            Lista.Cambio += new ManejadorEventosCambio(ListaCambio);
        }

Si añadimos un objeto a la lista, en el programa principal llamaremos a:
 lista.Add("Objeto 1");

Al ejecutar esta línea, el programa ejecuta el método Add definido de la siguiente manera:
public override int Add(object valor)
        {
            int i = base.Add(valor);
            HayCambio(EventArgs.Empty);
            return i;
        }

Cuando se invoca al evento HayCambio ejecuta el método del mismo nombre
Definido así:
//Invoca el evento Cambio; Se llama cuando la lista cambia
        protected virtual void HayCambio(EventArgs e)
        {
            if (Cambio != null)
                Cambio(this, e);
        }

En el caso de que haya un cambio llama a ListaCambio a través de la instrucción Cambio(this,e); El evento ListaCambio se dispara cada vez que cambia la lista.

        private void ListaCambio(object sender, EventArgs e)
        {
            Console.WriteLine("Esto se llama cuando se dispara el evento.");
        }
Que muestra en pantalla un texto. Este método es el que debe contener el código que deseamos ejecutar cuando se dispara un evento, en este caso muestra en pantalla el texto "Esto se llama cuando se dispara el evento."
A continuación limpiamos la lista ejecutando:
lista.Clear();
Esto ejecuta el método Clear definido de la siguiente manera:
public override void Clear()
        {
            base.Clear();
            HayCambio(EventArgs.Empty);
        }

Al ejecutar la llamada a HayCambio dispara de nuevo el evento repitiendo la misma secuencia de operaciones  que la explicada anteriormente para  lista.Add("Objeto 1"); Finalmente se llama a escuchador.Desvincula(); para desvincular la lista del evento. Esta acción ejecuta este método
public void Desvincula()
        {
    
            // Desvincula el evento y elimina la lista.
            Lista.Cambio -= new ManejadorEventosCambio(ListaCambio);
            Lista = null;
        }
A continuación el programa completo:
using System;
namespace Colecciones
{
    using System.Collections;

    // Un tipo de delegado para conectar las notificaciones de cambios.
    public delegate void ManejadorEventosCambio(object sender, EventArgs e);

    //Una clase que funciona igual que ArrayList, pero envía notificaciones de eventos cada vez que cambia la lista.
    public class EventoCambiaLista : ArrayList
    {
       
        //Un evento que los clientes pueden usar para notificar cuando cambian los elementos de la lista.
        public event ManejadorEventosCambio Cambio;

        //Invoca el evento Cambio; Se llama cuando la lista cambia
        protected virtual void HayCambio(EventArgs e)
        {
            if (Cambio != null)
                Cambio(this, e);
        }

       //Sobrecarga algunos métodos que pueden cambiar la lista, invoca el evento después de cada llamada
        public override int Add(object valor)
        {
            int i = base.Add(valor);
            HayCambio(EventArgs.Empty);
            return i;
        }

        public override void Clear()
        {
            base.Clear();
            HayCambio(EventArgs.Empty);
        }

        public override object this[int indice]
        {
            set
            {
                base[indice] = value;
                HayCambio(EventArgs.Empty);
            }
        }
    }
}

namespace TesteaEventos
{
    using Colecciones;

    class EscuchaEvento
    {
        private EventoCambiaLista Lista;

        public EscuchaEvento(EventoCambiaLista lista)
        {
            Lista = lista;

            //Se añade "ListaCambio" al evento Cambio de Lista.
            Lista.Cambio += new ManejadorEventosCambio(ListaCambio);
        }

        // Se llamará cada vez que cambie la lista.
        private void ListaCambio(object sender, EventArgs e)
        {
            Console.WriteLine("Esto se llama cuando se dispara el evento.");
        }

        public void Desvincula()
        {
    
            // Desvincula el evento y elimina la lista.
            Lista.Cambio -= new ManejadorEventosCambio(ListaCambio);
            Lista = null;
        }
    }

    class Testea
    {
        // Programa principal. Testea el evento de la clase EventoCambiaLista.
        public static void Main()
        {
            // Crea una nueva lista.
            EventoCambiaLista lista = new EventoCambiaLista();

            // Crea una clase que escucha los eventos de cambio de la lista.
            EscuchaEvento escuchador = new EscuchaEvento(lista);

            // Añade y elimina objetos de la lista.
            lista.Add("Objeto 1");
            lista.Clear();
            escuchador.Desvincula();
        }
    }
}


Eventos y herencia

Si de un componente se pueden derivar clases, es posible que haya  problemas con los eventos. Como los eventos sólo se pueden invocar desde la clase que los declaró, las clases derivadas no pueden invocar eventos declarados dentro de la clase base.

Pero hay veces que es mejor dar a la clase derivada la libertad de invocar el evento.  Para hacer esto se  crea un método de invocación protegido para el evento.  Luego se llama a este método y así  las clases derivadas pueden invocar el evento. El método que invoca se declarar como virtual para tener mayor flexibilidad.

Eventos en interfaces

Un evento también se puede colocar en una interfaz. Cuando se implementa la interfaz, la clase que la implementa debe suministrar el evento correspondiente en la clase que implementa la interfaz.

 Requisitos de eventos para .NET Framework


El tipo delegado utilizado para un evento debe aceptar dos parámetros: un parámetro "origen del objeto" que indique el origen del evento y un parámetro "e" que encapsule cualquier información adicional acerca del evento. El tipo del parámetro "e" debe derivarse de la clase EventArgs. Para eventos que no utilizan información adicional, .NET Framework tiene ya definido un tipo delegado apropiado: EventHandler.


A continuación una versión modificada del ejemplo anterior:

Al ejecutar el programa principal, sigue una secuencia similar a la del primer programa solo que ahora utiliza el delegado perteneciente al framework llamado EventHandler por lo que no es necesario crear un delegado ManejadorEventosCambio como en el primer ejemplo.

El funcionamiento del programa es idéntico.  Aquí el código completo del programa:

using System;
namespace MiColeccion
{
    using System.Collections;

   
    //Esta clase funciona como ArrayList, pero envía notificaciones de eventos cada vez que cambia la lista:
    public class EventoCambiaLista : ArrayList
    {

        //Un evento que los clientes pueden utilizar para ser notificado cada vez que cambien los elementos de la lista:
        public event EventHandler Cambio;

        //Invoca el evento Cambio; Cuando hay un cambio en la lista:
        protected virtual void HayCambio(EventArgs e)
        {
            if (Cambio != null)
                Cambio(this, e);
        }

   
        //Sobreescribe algunos métodos que pueden cambiar la lista; Invoca el evento
        public override int Add(object valor)
        {
            int i = base.Add(valor);
            HayCambio(EventArgs.Empty);
            return i;
        }

        public override void Clear()
        {
            base.Clear();
            HayCambio(EventArgs.Empty);
        }

        public override object this[int indice]
        {
            set
            {
                base[indice] = value;
                HayCambio(EventArgs.Empty);
            }
        }
    }
}

namespace TesteaEventos
{
    using MiColeccion;

    class EscuchaEvento
    {
        private EventoCambiaLista Lista;

        public EscuchaEvento(EventoCambiaLista lista)
        {
            Lista = lista;
            //Añade "ListaCambio" al evento de cambio en "Lista";
            Lista.Cambio += new EventHandler(ListaCambio);
        }

        // Se llamará cada vez que cambie la lista:
        private void ListaCambio(object sender, EventArgs e)
        {
            Console.WriteLine("Se llama cuando se dispara el evento.");
        }

        public void Detach()
        {
          
            //Saca el evento y lo elimina de la lista
            Lista.Cambio -= new EventHandler(ListaCambio);
            Lista = null;
        }
    }

    class Testeo
    {
        // Testea la clase EventoCambiaLista:
        public static void Main()
        {
            // Crea una nueva lista
            EventoCambiaLista lista = new EventoCambiaLista();

            // Crea una clase que escucha el evento cambio de la lista:
            EscuchaEvento escuchador = new EscuchaEvento(lista);

            // Añade y elimina objetos de la lista:
            lista.Add("objeto 1");
            lista.Clear();
            escuchador.Detach();
        }
    }
}






No hay comentarios:

Publicar un comentario