2010-09-24 15 views
7

Wenn ich AddHandler in VB verwenden meine eigene Methode, um das Click-Ereignis hinzuzufügen:Hinzufügen von eigenen Event-Handler vor anderen Event-Handler

AddHandler Button.Click, AddressOf myButton_Click 

Ich sehe, dass mein Code zuletzt führt - nach anderen Event-Handler für die Button_Click-Ereignis Gibt es eine Möglichkeit, meinen Event-Handler vor anderen anderen Ereignissen einzufügen, damit es zuerst ausgeführt wird?

Ich habe diese Frage sowohl als C# als auch VB markiert, bitte zögern Sie entweder Sprache zu verwenden, wenn Sie irgendwelche Vorschläge haben.
Danke!

Antwort

5

Die Reihenfolge der Ausführung der Handler eines einzelnen Ereignisses kann nicht durch das Grundverhalten eines integrierten Ereignis selbst gesteuert werden. MulticastDelegates sind "Taschen" von Handlern, und sie greifen sie nur einzeln an. Denken Sie daran, dass dies von den meisten Entwicklern erwartet wird und dass es gefährlich sein kann, auftragsabhängige Ereignisbehandlungsroutinen zuzulassen. Event-Handler sollten normalerweise nicht voneinander wissen, denn wenn sie davon abhängig sind, vor oder nach einem anderen Handler ausgeführt zu werden, müssen sie zuerst von der Existenz des anderen Handlers wissen (Verletzung des Verbergens von Informationen und anderer Design-Prinzipien). Wenn sich diese Reihenfolge ändert, wird das Verhalten unterbrochen.

Wenn Sie all dies verstehen und trotzdem die Ausführungsreihenfolge von Handlern eines Ereignisses steuern möchten, kommen Sie mit folgenden Schritten in die Nähe.

  1. Erstellen Sie eine geordnete Sammlung von Delegaten des Ereignishandlertyps namens MyHandlers. Dies wird ein Surrogat für die MulticastDelegate-Implementierung des tatsächlichen Ereignisses sein.
  2. Erstellen Sie eine "Master" -Handlermethode, die tatsächlich an das integrierte Ereignis angehängt wird, und durch MyHandlers iterieren und jedes aufrufen.
  3. Definieren Sie einige Mittel zum Hinzufügen und Entfernen von Handlern aus der Liste. Einiges davon kann mit einer benutzerdefinierten Ereignis- "Eigenschaft" erreicht werden, aber das definiert nur Verhalten hinzufügen und entfernen, nicht einfügen.

Der Code könnte wie folgt aussehen:

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; 

Beachten Sie, dass Sie nicht mehr Handler andere als MasterClickHandler dem eigentlichen Ereignis Befestigung; Sie können Ihren Kuchen nicht essen und auch nicht essen, indem Sie das grundlegende Ereignisverhalten außer Kraft setzen und behalten.In das Ereignis "property" ist auch kein "insert" -Verhalten eingebaut; Sie müssen eine Methode definieren, die dies erlaubt. Schließlich sollten Sie das Ereignis MyControlButtonClick niemals direkt auslösen (obwohl Ihr Steuerelement das einzige ist, das dies kann, kann dies durch eine Codeüberprüfung erzwungen werden).

Nun, wenn Sie auf die Schaltfläche klicken, wird das Click-Ereignis in integrierten die Taste feuert MasterEventHandler, die die Delegierten in MyHandlers in der gleichen Reihenfolge ausgeführt werden diese auf MyControlButtonClick angebracht wurden (mit einer, der zuerst ausgeführt eingefügt wurden, in umgekehrter Reihenfolge wurden sie eingefügt). Wenn Sie diesen Code mit dem Button in ein benutzerdefiniertes Benutzersteuerelement eingefügt haben, könnten Sie sogar das benutzerdefinierte Ereignis auf Ihrem Steuerelement als Click bezeichnen. Das Steuerelement würde genauso aussehen und funktionieren wie der enthaltene Button, außer dass es zusätzliche Kontrolle über das Einfügen hätte Handler. Das Schöne an der ganzen Sache ist, dass nichts an diesem Code die Verbraucher dazu zwingt, mit ihr als etwas anderes als einem einfachen ol vanilla Event zu arbeiten.

11

Nicht leicht.

Das gesagt, tun Sie es nicht. Ihr Code sollte sich nicht darum kümmern, in welcher Reihenfolge er aufgerufen wird - es sollte nur darauf achten, dass auf den betreffenden Button geklickt wurde. Alle Handler, einschließlich Ihrer, werden ausgeführt. Wenn die Reihenfolge wichtig ist, sollten Sie Ihr Design überdenken und einen anderen Mechanismus verwenden, um das zu steuern.

+0

+1 für den guten Rat. –

4

Es ist eher ein Implementierungsdetail von VB.NET, es hat eine alternative Möglichkeit, mit Ereignissen umzugehen, die die Schlüsselwörter WithEvents und Handles verwenden. Ein Ereignishandler, der Handles verwendet, wird von automatisch generiertem Code im Formularkonstruktor abonniert. Dieser Code wird vor jedem Code ausgeführt, einschließlich InitializeComponent oder Ihrer benutzerdefinierten AddHandler-Anweisung. Und wird also immer zuerst laufen.

Es ist möglich, Ihren Code zu erhalten, damit er als erster ausgeführt werden kann. Leiten Sie Ihre eigene Klasse von Knopf und überschreiben Sie die OnClick-Methode:

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

Ich hatte ein ähnliches Problem.

Ich hatte ein Ereignis: Geschlossen, dass zwei verschiedene Objekte zu hören. Und ich musste sicher sein, dass das Ereignis des ersten Objekts vor dem zweiten aufgerufen wird.

Hier seine meine Lösung (in 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); 
     } 
    } 
} 

diese Weise für alle Ereignisse zuerst genannt Ich möchte sein:

m_Screen.Closed += Screen_Closed; 

Und für alle Ereignisse, die ich genannt werden wollen zuletzt:

m_Screen.ScreenRemoved += new EventHandler(Screen_Closed); 

* beide Art und Weise ein Ereignis Zugabe sind die gleichen, mit und ohne "new Eventhandler()"

Ich hoffe, ich war hilfreich.