2009-02-16 16 views
8

Estoy tratando de añadir y eliminar eventos de un temporizador y tengo el siguiente código:C# añadir y eliminar eventos de un temporizador

Timer myTimer = new Timer(); // Windows.Forms Timer 

public void addEvent(MyDelegate ev) 
{ 
    myTimer.Tick += new EventHandler(ev); 
} 

public void removeEvent(MyDelegate ev) 
{ 
    myTimer.Tick -= new EventHandler(ev); 
} 

No sé si estoy haciendo nada estúpido al tratar de añadir y elimine a los delegados de esta manera, puedo agregar delegados y hacer que actúen como se espera. Sin embargo, cuando intento eliminar los eventos, continúan activando Timers Tick.

¿Alguien puede ver algo obviamente mal?

+0

Podría mostrar el definiton de MyDelegate y explicar por qué está ahí? –

Respuesta

8

creo que este código:

myTimer.Tick -= new EventHandler(ev); 

crea un nuevo objeto manejador de sucesos. Nunca eliminará un EventHandler existente. Para obtener la funcionalidad que desea, debe estar pasando en manejadores de sucesos, no MyDelegates, al añadir y eliminar métodos:

Timer myTimer = new Timer(); // Windows.Forms Timer 

public void addEvent(EventHandler ev) 
{ 
    myTimer.Tick += ev; 
} 

public void removeEvent(EventHandler ev) 
{ 
    myTimer.Tick -= ev; 
} 

El código de llamada tendrán que realizar un seguimiento de los manejadores de sucesos añadió, por lo que puede pasar en el mismo objeto EventHandler cuando es el momento de darse de baja.

+1

El código funciona como está: no es necesario que el código de llamada mantenga una lista de Manejadores de eventos. El almacén de respaldo del evento buscará el delegado real y eliminará el proprt ivocationItem. Puede llamar a removeEvent (MyTickHandler); –

+0

¡Sabía que estaba teniendo un momento de bloqueador de codificadores allí! Tiene razón al decir que funciona EventHandlers en lugar de Delegates. ¡Gracias por tu ayuda! –

1

Usted sólo debe ser capaz de darse de baja haciendo referencia al nombre de su método aún el manejo de este modo:

public void removeEvent(MyDelegate ev) 
{ 
    myTimer.Tick -= ev as EventHandler; 
} 
+0

Desafortunadamente, esto produce un error de compilación "No se puede convertir implícitamente el tipo 'myDelegate' a 'System.EventHandler'" –

+0

Eso no haría ninguna diferencia. Si omite el nuevo EventHandler (...) o constructores similares, se agregan al compilar. – Samuel

+0

¿Puedes lanzarlo sin embargo? –

0

Al añadir y eliminar controladores de eventos que va a crear un nuevo contenedor para su delegado cada vez. Por lo tanto, en su método de eliminación está intentando eliminar un nuevo objeto EventHandler que nunca se agregó como escucha al evento en primer lugar.

Si desea seguir usando este tipo de configuración, tal vez pueda colocar sus manejadores de eventos en un diccionario. En el método addEvent, inserte su EventHandler recién creado en su diccionario, y en el método removeEvent, extraiga el EventHandler del diccionario y elimínelo en lugar de crear uno nuevo.

2

Su problema proviene de tener métodos de ayuda para hacer esto. Sin ellos, funciona como se esperaba, con ellos no sabe qué desenganchar.

Para arreglar esto, necesitará mantener un diccionario con el valor que es el manejador de eventos creado en el método de enganche para que pueda eliminar ese valor más adelante.

Algo así como:

var handlers = new Dictionary<MyDelegate, EventHandler>(); 

public void addEvent(MyDelegate ev) 
{ 
    var handler = new EventHandler(ev); 
    handlers.Add(ev, handler); 
    myTimer.Tick += handler; 
} 

public void removeEvent(MyDelegate ev) 
{ 
    myTimer.Tick -= handlers[ev]; 
} 

se debe añadir los controles adecuados si existe el elemento.

También podría cambiar su tipo de parámetro y funcionará como se esperaba.

public void addEvent(EventHandler ev) 
{ 
    myTimer.Tick += ev; 
} 

public void removeEvent(EventHandler ev) 
{ 
    myTimer.Tick -= ev; 
} 

addEvent(new EventHandler(...)); 
removeEvent(new EventHandler(...)); 
0

No sé lo que estás haciendo mal, pero el enfoque habitual que yo usaría para temporizadores sería suscribirse al evento Tick, y luego desactivar el temporizador cuando no se desea recibir los eventos, volviendo a habilitar cuando lo haga.

Puede que no te ayuden si tienes más de un controlador de eventos conectado al evento, pero espero que sea de alguna utilidad.

3

El código inicial funciona bien, siempre y cuando el MyDelegate 'ev' pasó a addEvent y removeEvent es la misma instancia de objeto (por ejemplo, si hay un campo de nivel de clase MyDelegate que contiene la instancia o si sigue el consejo de varios otros aquí y guarde el objeto (s) MyDelegate en un Diccionario).

Sospecho que el problema es que el código de llamada addEvent y removeEvent está pasando nuevos MyDelegate casos apuntando a algún método de control, así:

addEvent(new MyDelegate(this.HandlerMethod)); 
// ... do some stuff 
removeEvent(new MyDelegate(this.HandlerMethod)); 

En cuyo caso addEvent y removeEvent están creando EventHandler delegados que apuntan a direcciones de métodos diferentes, aunque esos delegados a su vez están apuntando al mismo método (this.HandlerMethod). Esto se debe a que el EventHandler delega que add y remove crean un punto para el método MyDelegate.Invoke() en diferentes instancias de MyDelegate en lugar de hacerlo directamente en la dirección de this.HandlerMethod.

+1

Además de las sospechas del bufón, esto también puede ocurrir si la persona que llama simplemente pasa el nombre de un método que coincide con la firma del delegado, por ejemplo, addEvent (this.MyCallback) ;. En este caso, el delegado se crea implícitamente, lo que lleva al problema descrito. –

0

Esto debería funcionar:

private void timer_Tick(object sender, EventArgs e) 
{ 
    try 
    { 
     // Disallow re-entry 
     timer.Tick -= timer_Tick; 
     . . . 
    } 
    finally 
    { 
     timer.Tick += timer_Tick; 
    } 
}