Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
[Tutoria] C# Eventos [Dificil]
#1


Tutorial de eventos
Visual Studio .NET 2003
Este tutorial explica cómo declarar, llamar y enlazar eventos en C#.

Archivos de ejemplo

Vea Ejemplo de eventos para descargar y generar los archivos de ejemplo que se utilizan en este tutorial.

Información adicional

evento
delegate
Controlar y provocar eventos
Tutorial de delegados
Introducción a los controladores de eventos en formularios Windows Forms
Tutorial

Un evento en C# es el modo que tiene una clase de proporcionar notificaciones a los clientes de la clase cuando ocurre algo digno de reseñar en un objeto. El uso más habitual para los eventos se produce en las interfaces gráficas; normalmente, las clases que representan controles de la interfaz disponen de eventos que se notifican cuando el usuario hace algo con el control (por ejemplo, hacer clic en un botón).

Los eventos, sin embargo, no sólo se utilizan para interfaces gráficas. Los eventos proporcionan un medio apropiado para que los objetos puedan señalizar cambios de estado que pueden resultar útiles para los clientes de ese objeto. Los eventos constituyen unidades importantes para crear clases que se pueden reutilizar en diferentes programas.

Los eventos se declaran mediante delegados. Si aún no ha estudiado el Tutorial de delegados, debería hacerlo antes de continuar. Recuerde que un objeto delegado encapsula un método de modo que se pueda llamar de forma anónima. Un evento es el modo que tiene una clase de permitir a los clientes proporcionar delegados a los métodos para llamarlos cuando se produce el evento. Cuando ocurre el evento, se llama a los delegados que proporcionan los clientes para el evento.

Además de los ejemplos sobre declaración, llamada y enlace a eventos, este tutorial también incluye los siguientes temas:

Eventos y herencia
Eventos en interfaces
Instrucciones para .NET Framework
Ejemplo 1

El siguiente ejemplo muestra una clase, ListWithChangedEvent, similar a la clase estándar ArrayList, pero también llama a un evento Changed cuando el contenido de la lista cambia. Una clase de propósito general como esa podría utilizarse de muchas formas en un programa extenso.

Por ejemplo, un procesador de textos podría mantener una lista de los documentos abiertos. Cuando la lista cambia, puede que sea necesario notificarlo a diferentes objetos del procesador de textos para poder actualizar la interfaz de usuario. Mediante el uso de eventos, el código que mantiene la lista de documentos no necesita saber quién necesita notificación (una vez que se cambia la lista de documentos, se llama automáticamente al evento y se notifica correctamente a todos los objetos que lo necesitan). Mediante el uso de eventos, la modularidad del programa se incrementa.

// events1.cs
using System;
namespace MyCollections
{
using System.Collections;

// A delegate type for hooking up change notifications.
public delegate void ChangedEventHandler(object sender, EventArgs e);

// A class that works just like ArrayList, but sends event
// notifications whenever the list changes.
public class ListWithChangedEvent: ArrayList
{
// An event that clients can use to be notified whenever the
// elements of the list change.
public event ChangedEventHandler Changed;

// Invoke the Changed event; called whenever list changes
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this, e);
}

// Override some of the methods that can change the list;
// invoke event after each
public override int Add(object value)
{
int i = base.Add(value);
OnChanged(EventArgs.Empty);
return i;
}

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

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

namespace TestEvents
{
using MyCollections;

class EventListener
{
private ListWithChangedEvent List;

public EventListener(ListWithChangedEvent list)
{
List = list;
// Add "ListChanged" to the Changed event on "List".
List.Changed += new ChangedEventHandler(ListChanged);
}

// This will be called whenever the list changes.
private void ListChanged(object sender, EventArgs e)
{
Console.WriteLine("This is called when the event fires.");
}

public void Detach()
{
// Detach the event and delete the list
List.Changed -= new ChangedEventHandler(ListChanged);
List = null;
}
}

class Test
{
// Test the ListWithChangedEvent class.
public static void Main()
{
// Create a new list.
ListWithChangedEvent list = new ListWithChangedEvent();

// Create a class that listens to the list's change event.
EventListener listener = new EventListener(list);

// Add and remove items from the list.
list.Add("item 1");
list.Clear();
listener.Detach();
}
}
}
Resultado

This is called when the event fires.
This is called when the event fires.
Descripción del código

Declaración de un evento Para declarar un evento dentro de una clase, primero debe declararse un tipo delegado para el evento si aún no existe uno declarado.
public delegate void ChangedEventHandler(object sender, EventArgs e);
El tipo delegado define el conjunto de argumentos que se pasan al método que realiza el tratamiento del evento. Varios eventos pueden compartir el mismo tipo delegado, de modo que este paso sólo es necesario si aún no se ha declarado ningún tipo delegado.

A continuación, se declara el propio evento.

public event ChangedEventHandler Changed;
Un evento se declara como un campo de tipo delegado, con la diferencia de que la palabra clave event precede a la declaración de evento, a continuación de los modificadores. Los eventos se suelen declarar como públicos, pero se permite cualquier otro modificador de accesibilidad.

Llamada a un evento Una vez que una clase derivada ha declarado un evento, puede tratar el evento simplemente como un campo del tipo delegado indicado. El campo puede tomar el valor null, si ningún cliente ha enlazado un delegado al evento, o bien un valor que hace referencia al delegado que se debería utilizar cuando se produce el evento. De este modo, la llamada a un evento se realiza generalmente comprobando primero el valor null y después llamando al evento.
if (Changed != null)
Changed(this, e);
La llamada a un evento sólo se puede hacer desde dentro de la clase que declaró el evento.

Enlace a un evento Desde fuera de la clase que lo declaró, un evento es similar a un campo, pero el acceso a ese campo es muy restringido. Las únicas cosas que se pueden hacer son:
Componer un nuevo delegado sobre ese campo.
Quitar un delegado de un campo (posiblemente compuesto).
Esto se hace mediante los operadores += y -=. Para empezar a recibir llamadas a eventos, el código del cliente crea primero un delegado del tipo del evento que hace referencia al método que se debería invocar desde el evento. A continuación, adjunta ese delegado, mediante el operador +=, a cualquier otro delegado con el que el evento deba estar conectado.

// Add "ListChanged" to the Changed event on "List":
List.Changed += new ChangedEventHandler(ListChanged);
Cuando el código del cliente termina de recibir llamadas al evento, quita su delegado del evento mediante el operador -=.

// Detach the event and delete the list:
List.Changed -= new ChangedEventHandler(ListChanged);
Eventos y herencia

Cuando se crea un componente general del que se pueden derivar clases, se pueden producir supuestos problemas con los eventos. Como los eventos sólo se pueden invocar desde dentro de la clase que los declaró, las clases derivadas no pueden invocar directamente eventos declarados dentro de la clase base. Aunque, a veces, esto es lo deseado, a menudo resulta apropiado dar a la clase derivada la libertad de invocar el evento. Esto se realiza normalmente creando un método de invocación protegido para el evento. Mediante la llamada a este método invocatorio, las clases derivadas pueden invocar el evento. Para obtener más flexibilidad, el método que invoca se suele declarar como virtual, lo cual permite a la clase derivada reemplazarlo. Esto permite a la clase derivada interceptar los eventos que la clase base está invocando, y, posiblemente, realizar su propio procesamiento sobre ellos.

En el ejemplo anterior, esto se ha realizado con el método OnChanged. Una clase derivada podría invocar o reemplazar este método si fuera necesario.

Eventos en interfaces

Otra diferencia entre eventos y campos es que un evento se puede colocar en una interfaz mientras que un campo no. Cuando se implementa la interfaz, la clase que la implementa debe suministrar un evento correspondiente en la clase que implementa la interfaz.

Instrucciones para .NET Framework

Aunque el lenguaje C# permite a los eventos utilizar cualquier tipo delegado, .NET Framework tiene algunas instrucciones más estrictas sobre los tipos delegados que se deben utilizar para los eventos. Si piensa utilizar el componente con .NET Framework, es recomendable que siga estas instrucciones.

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

Ejemplo 2

El siguiente ejemplo es una versión modificada del Ejemplo 1 que sigue las instrucciones de .NET Framework. El ejemplo utiliza el tipo delegado EventHandler.

// events2.cs
using System;
namespace MyCollections
{
using System.Collections;

// A class that works just like ArrayList, but sends event
// notifications whenever the list changes:
public class ListWithChangedEvent: ArrayList
{
// An event that clients can use to be notified whenever the
// elements of the list change:
public event EventHandler Changed;

// Invoke the Changed event; called whenever list changes:
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this,e);
}

// Override some of the methods that can change the list;
// invoke event after each:
public override int Add(object value)
{
int i = base.Add(value);
OnChanged(EventArgs.Empty);
return i;
}

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

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

namespace TestEvents
{
using MyCollections;

class EventListener
{
private ListWithChangedEvent List;

public EventListener(ListWithChangedEvent list)
{
List = list;
// Add "ListChanged" to the Changed event on "List":
List.Changed += new EventHandler(ListChanged);
}

// This will be called whenever the list changes:
private void ListChanged(object sender, EventArgs e)
{
Console.WriteLine("This is called when the event fires.");
}

public void Detach()
{
// Detach the event and delete the list:
List.Changed -= new EventHandler(ListChanged);
List = null;
}
}

class Test
{
// Test the ListWithChangedEvent class:
public static void Main()
{
// Create a new list:
ListWithChangedEvent list = new ListWithChangedEvent();

// Create a class that listens to the list's change event:
EventListener listener = new EventListener(list);

// Add and remove items from the list:
list.Add("item 1");
list.Clear();
listener.Detach();
}
}
}
Resultado

This is called when the event fires.
This is called when the event fires.


Posibles temas similares...
Tema Autor Respuestas Vistas Último mensaje
  reCAPTCHA: fácil para humanos, ¿difícil para bots? Kevin9908 3 305 30-06-2015, 08:13 PM
Último mensaje: garcon
  [Tutoria] C# Implementación explícita de interfaces Postteandox 0 536 21-11-2011, 01:23 AM
Último mensaje: Postteandox
  [Tutoria] C# Conversaciones Indefinidas por El Usuario Postteandox 0 473 21-11-2011, 01:18 AM
Último mensaje: Postteandox



Usuarios navegando en este tema: 1 invitado(s)