2010-09-24 18 views
7

Cuando utilizo AddHandler en VB añadir mi propio método para el evento Click:Adición propio controlador de eventos frente a otros controladores de eventos

AddHandler Button.Click, AddressOf myButton_Click 

veo que mi código se ejecuta pasado - después de que otros controladores de eventos para el Evento Button_Click. ¿Hay alguna manera de insertar mi controlador de eventos al frente de otros eventos para que se ejecute primero?

He etiquetado esta pregunta como C# y VB, no dude en utilizar cualquiera de los dos idiomas si tiene alguna sugerencia.
Gracias!

Respuesta

5

El orden de ejecución de los manipuladores de un solo evento no pueden ser controlados a través del comportamiento básico de un built-in evento en sí. Los delegados de Multicast son "bolsas" de manipuladores, y simplemente los agarran uno a la vez. Tenga en cuenta que así es como la mayoría de los desarrolladores esperan que esto funcione, y puede ser peligroso permitir manipuladores de eventos dependientes del pedido. Los manejadores de eventos normalmente no deberían conocerse entre sí, porque si dependen de que se ejecuten antes o después de otro manejador, primero deben saber de la existencia del otro manejador (que viola el ocultamiento de información y varios otros principios de diseño), y segundo, si ese orden cambia, el comportamiento se romperá.

Si entiende todo esto y aún desea controlar el orden de ejecución de los controladores de un evento, lo siguiente lo acercará.

  1. Cree una colección ordenada de delegados del tipo de controlador de eventos llamado MyHandlers. Este será un sustituto de la implementación MulticastDelegate del evento real.
  2. Crea un método de controlador "maestro" que realmente se adjuntará al evento integrado, y se repetirá a través de MyHandlers y llamará a cada uno.
  3. Define algunos medios para agregar y eliminar controladores de la lista. Parte de esto se puede lograr con una "propiedad" de evento personalizado, pero eso solo definirá agregar y eliminar comportamientos, no insertar.

El código podría tener el siguiente aspecto:

private List<EventHandler> MyHandlers = new List<EventHandler>(); 

private void MasterClickHandler(object sender, EventArgs e) 
{ 
    foreach(var handler in MyHandlers) 
     handler(sender, e); 
} 

public event EventHandler MyControlButtonClick 
{ 
    add { MyHandlers.Add(value); } 
    remove { MyHandlers.Remove(value); } 
} 

public void InsertButtonClickHandler(EventHandler handler) 
{ 
    MyHandlers.Insert(handler,0); //calling this to add a handler puts the handler up front 
} 

... 

myForm.MyControl.Click += MasterClickHandler; 

en cuenta que ya no está adjuntando los controladores que no sean MasterClickHandler al acontecimiento real; no puedes tener tu pastel y comértelo también, anulando y manteniendo el comportamiento básico del evento.Tampoco hay un comportamiento de "inserción" incorporado en la "propiedad" del evento; tienes que definir un método que lo permita. Por último, nunca debe plantear el evento MyControlButtonClick directamente (aunque como su control es el único que puede hacerlo, esto se puede aplicar mediante la inspección del código).

Ahora, al hacer clic en el botón, el evento Click integrado del botón dispara MasterEventHandler, que ejecutará los delegados en MyHandlers en el mismo orden en que se adjuntaron a MyControlButtonClick (con el que se insertó se ejecutó primero, en el reverso orden en que fueron insertados). Si coloca este código en un control de usuario personalizado con el Botón, incluso podría nombrar el evento personalizado en su control Haga clic en, y el control se vería y funcionaría de manera similar al Botón que contiene, excepto que tendría el control adicional sobre la inserción manejadores. La belleza de todo esto es que nada acerca de este código obliga a los consumidores a trabajar con él como algo más que un simple evento de vanilla.

11

No es fácil.

Dicho esto, no lo hagas. A su código no debería importarle el orden en que lo llama; debería preocuparse de que se haya hecho clic en el botón en cuestión. Todos los controladores, incluido el tuyo, se ejecutarán. Si el orden es importante, debe reconsiderar su diseño y utilizar algún otro mecanismo para controlarlo.

+0

+1 por el buen consejo. –

4

Es más un detalle de implementación de VB.NET, tiene una forma alternativa de tratar los eventos utilizando las palabras clave WithEvents y Handles. Un controlador de eventos que utiliza Handles se suscribe por código generado automáticamente en el constructor de formulario. Este código se ejecutará antes que cualquiera de sus códigos, incluidos InitializeComponent o su declaración AddHandler personalizada. Y por lo tanto, siempre se ejecutará primero.

Es posible obtener su código para garantizar que se ejecute primero. Derivar su propia clase de Button y reemplazar el método OnClick:

Public Class MyButton 
    Inherits Button 

    Protected Overrides Sub OnClick(ByVal e As System.EventArgs) 
     '' Do your stuff here 
     ''.... 

     '' Other event handlers will run now: 
     MyBase.OnClick(e) 
    End Sub 
End Class 
2

Tuve un problema similar.

Tuve un evento: Cerrado que dos objetos diferentes escuchan. Y tenía que estar seguro de que se convocaría el evento del primer objeto antes del segundo.

Aquí su mi solución (en C#):

public class Screen 
{ 
    public event EventHandler Closed; 
    public event EventHandler ScreenRemoved; 


    protected virtual void OnClosed() 
    { 
     if (Closed != null) 
     { 
      Closed.Invoke(this, EventArgs.Empty); 
     } 

     OnScreenRemoved(); 
    } 

    protected virtual void OnScreenRemoved() 
    { 
     if (ScreenRemoved != null) 
     { 
      ScreenRemoved.Invoke(this, EventArgs.Empty); 
     } 
    } 
} 

esta manera para todos los eventos a los que quieren ser llamados en primer lugar:

m_Screen.Closed += Screen_Closed; 

Y para todos los eventos a los que quieren ser llamados última:

m_Screen.ScreenRemoved += new EventHandler(Screen_Closed); 

* de cualquier manera la adición de un evento son los mismos, con y sin "nuevo manejador de sucesos()"

Espero que haya sido útil.

Cuestiones relacionadas