c# - custom - vb.net event erstellen




Ereignisse und Ereignishandler in C#verstehen (6)

C # kennt zwei Begriffe, delegate und event . Beginnen wir mit dem ersten.

Delegieren

Ein delegate ist eine Referenz auf eine Methode. Genauso wie Sie einen Verweis auf eine Instanz erstellen können:

MyClass instance = myFactory.GetInstance();

Sie können einen Delegaten verwenden, um einen Verweis auf eine Methode zu erstellen:

Action myMethod = myFactory.GetInstance;

Nachdem Sie nun diese Referenz auf eine Methode haben, können Sie die Methode über die Referenz aufrufen:

MyClass instance = myMethod();

Aber warum solltest du? Sie können myFactory.GetInstance() auch direkt aufrufen. In diesem Fall können Sie. Es gibt jedoch viele Fälle, in denen Sie darüber nachdenken sollten, wo Sie nicht möchten, dass der Rest der Anwendung von myFactory Kenntnis myFactory oder myFactory.GetInstance() direkt myFactory.GetInstance() .

Eine offensichtliche ist, wenn Sie in der Lage sein möchten, myFactory.GetInstance() in myOfflineFakeFactory.GetInstance() von einer zentralen Stelle (aka Factory-Methode-Muster ) zu ersetzen.

Factory-Methode-Muster

Wenn Sie also eine TheOtherClass Klasse haben und die myFactory.GetInstance() , sieht der Code wie folgt aus (Sie müssen TheOtherClass über den Typ Ihrer myFactory ):

TheOtherClass toc;
//...
toc.SetFactory(myFactory);


class TheOtherClass
{
   public void SetFactory(MyFactory factory)
   {
      // set here
   }

}

Wenn Sie Delegaten verwenden möchten, müssen Sie den Typ meiner Factory nicht angeben:

TheOtherClass toc;
//...
Action factoryMethod = myFactory.GetInstance;
toc.SetFactoryMethod(factoryMethod);


class TheOtherClass
{
   public void SetFactoryMethod(Action factoryMethod)
   {
      // set here
   }

}

Auf diese Weise können Sie einer anderen Klasse einen Delegaten zuweisen, ohne den Typ für sie anzugeben. Das Einzige, was Sie angeben, ist die Signatur Ihrer Methode (wie viele Parameter Sie haben und so).

"Signatur meiner Methode", wo habe ich das vorher gehört? O ja, Schnittstellen !!! Schnittstellen beschreiben die Signatur einer ganzen Klasse. Stellen Sie sich Delegierte vor, die die Signatur nur einer Methode beschreiben!

Ein weiterer großer Unterschied zwischen einer Schnittstelle und einem Delegaten besteht darin, dass Sie beim Schreiben Ihrer Klasse nicht zu C # sagen müssen "diese Methode implementiert diesen Typ von Delegaten". Bei Schnittstellen müssen Sie sagen "Diese Klasse implementiert diesen Typ einer Schnittstelle".

Außerdem kann eine Delegatenreferenz (mit einigen Einschränkungen, siehe unten) auf mehrere Methoden ( MulticastDelegate ) verweisen. Dies bedeutet, dass beim Aufruf des Delegaten mehrere explizit angefügte Methoden ausgeführt werden. Eine Objektreferenz kann immer nur auf ein Objekt verweisen.

Die Einschränkungen für ein MulticastDelegate bestehen darin, dass die Signatur (Methode / Delegat) keinen Rückgabewert ( void ) haben sollte und die Schlüsselwörter out und ref nicht in der Signatur verwendet werden. Offensichtlich können Sie nicht zwei Methoden aufrufen, die eine Zahl zurückgeben und erwarten, dass sie die gleiche Zahl zurückgeben. Sobald die Signatur übereinstimmt, ist der Delegat automatisch ein MulticastDelegate .

Veranstaltung

Ereignisse sind nur Eigenschaften (wie die Felder get; set; properties to instance), die das Subskribent für den Delegaten von anderen Objekten verfügbar machen. Diese Eigenschaften unterstützen jedoch nicht get; set ;. Stattdessen unterstützen sie hinzufügen; entfernen;

So können Sie haben:

    Action myField;

    public event Action MyProperty
    {
        add { myField += value; }
        remove { myField -= value; }
    }

Verwendung in der Benutzeroberfläche (WinForms)

So, jetzt wissen wir, dass ein Delegat eine Referenz auf eine Methode ist und dass wir ein Ereignis haben können, um der Welt mitzuteilen, dass sie uns ihre Methoden geben kann, um von unserem Delegierten referenziert zu werden, und wir sind eine UI-Schaltfläche, dann: wir kann jeden fragen, der daran interessiert ist, ob ich geklickt wurde, um seine Methode bei uns zu registrieren (über die Veranstaltung, die wir aufgedeckt haben). Wir können all diese Methoden verwenden, die uns gegeben wurden, und sie durch unseren Delegierten referenzieren. Und dann werden wir warten und warten .... bis ein Benutzer kommt und auf diese Schaltfläche klickt, haben wir genug Gründe, den Delegierten aufzurufen. Und da der Delegat auf alle diese Methoden verweist, werden alle diese Methoden aufgerufen. Wir wissen nicht, was diese Methoden tun, noch wissen wir, welche Klasse diese Methode implementiert. Alles, was uns interessiert, ist, dass jemand daran interessiert war, dass wir geklickt wurden, und uns einen Hinweis auf eine Methode gab, die unserer gewünschten Unterschrift entsprach.

Java

Sprachen wie Java haben keine Delegierten. Sie verwenden stattdessen Schnittstellen. Die Art und Weise, wie sie das tun, besteht darin, jeden zu fragen, der daran interessiert ist, uns anzuklicken, eine bestimmte Schnittstelle zu implementieren (mit einer bestimmten Methode, die wir aufrufen können) und dann die gesamte Instanz anzugeben, die die Schnittstelle implementiert. Wir können eine Liste aller Objekte führen, die diese Schnittstelle implementieren, und können ihre "bestimmte Methode, die wir aufrufen können" aufrufen, wenn wir darauf klicken.

Ich verstehe den Zweck von Ereignissen, insbesondere im Zusammenhang mit der Erstellung von Benutzeroberflächen. Ich denke, das ist der Prototyp für das Erstellen eines Events:

public void EventName(object sender, EventArgs e);

Was machen Event-Handler, warum werden sie benötigt und wie kann ich einen erstellen?


Das ist eigentlich die Deklaration für einen Event-Handler - eine Methode, die aufgerufen wird, wenn ein Event ausgelöst wird. Um ein Ereignis zu erstellen, würden Sie Folgendes schreiben:

public class Foo
{
    public event EventHandler MyEvent;
}

Und dann können Sie die Veranstaltung wie folgt abonnieren:

Foo foo = new Foo();
foo.MyEvent += new EventHandler(this.OnMyEvent);

Mit OnMyEvent () definiert wie folgt:

private void OnMyEvent(object sender, EventArgs e)
{
    MessageBox.Show("MyEvent fired!");
}

Immer wenn Foo MyEvent , wird Ihr OnMyEvent Handler aufgerufen.

Sie müssen nicht immer eine Instanz von EventArgs als zweiten Parameter verwenden. Wenn Sie zusätzliche Informationen EventArgs EventArgs , können Sie eine von EventArgs abgeleitete Klasse EventArgs ( EventArgs ist die Basis nach Konvention). Wenn Sie sich beispielsweise einige Ereignisse ansehen, die unter Control in WinForms oder FrameworkElement in WPF definiert sind, können Sie Beispiele für Ereignisse sehen, die zusätzliche Informationen an die Ereignisbehandlungsroutinen übergeben.


Hier ist ein Codebeispiel, das helfen kann:

using System;
using System.Collections.Generic;
using System.Text;

namespace Event_Example
{
  // First we have to define a delegate that acts as a signature for the
  // function that is ultimately called when the event is triggered.
  // You will notice that the second parameter is of MyEventArgs type.
  // This object will contain information about the triggered event.

  public delegate void MyEventHandler(object source, MyEventArgs e);

  // This is a class which describes the event to the class that receives it.
  // An EventArgs class must always derive from System.EventArgs.

  public class MyEventArgs : EventArgs
  {
    private string EventInfo;

    public MyEventArgs(string Text) {
      EventInfo = Text;
    }

    public string GetInfo() {
      return EventInfo;
    }
  }

  // This next class is the one which contains an event and triggers it
  // once an action is performed. For example, lets trigger this event
  // once a variable is incremented over a particular value. Notice the
  // event uses the MyEventHandler delegate to create a signature
  // for the called function.

  public class MyClass
  {
    public event MyEventHandler OnMaximum;

    private int i;
    private int Maximum = 10;

    public int MyValue
    {
      get { return i; }
      set
      {
        if(value <= Maximum) {
          i = value;
        }
        else 
        {
          // To make sure we only trigger the event if a handler is present
          // we check the event to make sure it's not null.
          if(OnMaximum != null) {
            OnMaximum(this, new MyEventArgs("You've entered " +
              value.ToString() +
              ", but the maximum is " +
              Maximum.ToString()));
          }
        }
      }
    }
  }

  class Program
  {
    // This is the actual method that will be assigned to the event handler
    // within the above class. This is where we perform an action once the
    // event has been triggered.

    static void MaximumReached(object source, MyEventArgs e) {
      Console.WriteLine(e.GetInfo());
    }

    static void Main(string[] args) {
      // Now lets test the event contained in the above class.
      MyClass MyObject = new MyClass();
      MyObject.OnMaximum += new MyEventHandler(MaximumReached);
      for(int x = 0; x <= 15; x++) {
        MyObject.MyValue = x;
      }
      Console.ReadLine();
    }
  }
}

Ich stimme KE50 zu, außer dass ich das Schlüsselwort "event" als Alias ​​für "ActionCollection" ansehe, da das Ereignis eine Sammlung von auszuführenden Aktionen enthält (z. B. den Delegierten).

using System;

namespace test{

class MyTestApp{
    //The Event Handler declaration
    public delegate void EventAction();

    //The Event Action Collection 
    //Equivalent to 
    //  public List<EventAction> EventActions=new List<EventAction>();
    //        
    public event EventAction EventActions;

    //An Action
    public void Hello(){
        Console.WriteLine("Hello World of events!");
    }
    //Another Action
    public void Goodbye(){
        Console.WriteLine("Goodbye Cruel World of events!");
    }

    public static void Main(){
        MyTestApp TestApp = new MyTestApp();

        //Add actions to the collection
        TestApp.EventActions += TestApp.Hello;
        TestApp.EventActions += TestApp.Goodbye;

        //Invoke all event actions
        if (TestApp.EventActions!= null){
            //this peculiar syntax hides the invoke 
            TestApp.EventActions();
            //using the 'ActionCollection' idea:
            // foreach(EventAction action in TestApp.EventActions)
            //     action.Invoke();
        }
    }

}   

}

Nur um die bestehenden großen Antworten hier hinzuzufügen - aufbauend auf dem Code in der akzeptierten, die einen delegate void MyEventHandler(string foo) ...

Weil der Compiler den Delegattyp des SomethingHappened- Ereignisses kennt:

myObj.SomethingHappened += HandleSomethingHappened;

Ist völlig äquivalent zu:

myObj.SomethingHappened += new MyEventHandler(HandleSomethingHappened);

Und Handler können auch mit -= aufgehoben werden:

// -= removes the handler from the event's list of "listeners":
myObj.SomethingHappened -= HandleSomethingHappened;

Der Vollständigkeit halber kann das Hochfahren des Ereignisses nur in der Klasse durchgeführt werden, die das Ereignis besitzt:

//Firing the event is done by simply providing the arguments to the event:
var handler = SomethingHappened; // thread-local copy of the event
if (handler != null) // the event is null if there are no listeners!
{
    handler("Hi there!");
}

Die thread-lokale Kopie des Handlers wird benötigt, um sicherzustellen, dass der Aufruf Thread-sicher ist - andernfalls könnte ein Thread den letzten Handler für das Ereignis entfernen, nachdem wir überprüft haben, ob es null , und wir würden einen "Spaß" haben NullReferenceException dort.

C # 6 hat eine nette kurze Hand für dieses Muster eingeführt. Es verwendet den Null-Propagierungsoperator.

SomethingHappened?.Invoke("Hi there!");

Um Event-Handler zu verstehen, müssen Sie delegates verstehen. In C# können Sie sich einen Delegaten als Zeiger (oder Verweis) auf eine Methode vorstellen. Dies ist nützlich, da der Zeiger als Wert übergeben werden kann.

Das zentrale Konzept eines Delegierten ist seine Unterschrift oder Form. Das ist (1) der Rückgabetyp und (2) die Eingabeargumente. Wenn wir beispielsweise einen Delegaten void MyDelegate(object sender, EventArgs e) , kann er nur auf Methoden verweisen, die void und ein object und EventArgs . Ein bisschen wie ein quadratisches Loch und ein quadratischer Pflock. Wir sagen also, diese Methoden haben die gleiche Signatur oder Form wie der Delegierte.

Wenn wir wissen, wie man einen Verweis auf eine Methode erstellt, denken wir über den Zweck von Ereignissen nach: Wir möchten, dass ein bestimmter Code ausgeführt wird, wenn etwas anderswo im System passiert - oder "das Ereignis behandeln". Dazu erstellen wir spezifische Methoden für den Code, der ausgeführt werden soll. Das Bindeglied zwischen dem Ereignis und den auszuführenden Methoden sind die Delegierten. Das Ereignis muss intern eine "Liste" von Zeigern zu den Methoden enthalten, die aufgerufen werden, wenn das Ereignis ausgelöst wird. * Um eine Methode aufrufen zu können, müssen wir natürlich wissen, welche Argumente übergeben werden müssen! Wir verwenden den Delegaten als "Vertrag" zwischen dem Ereignis und allen spezifischen Methoden, die aufgerufen werden.

So stellt der Standard- EventHandler (und viele ähnliche) eine bestimmte Form der Methode dar (wiederum void / object-EventArgs). Wenn Sie ein Ereignis deklarieren, sagen Sie, welche Form der Methode (EventHandler) dieses Ereignis aufruft, indem Sie einen Delegaten angeben:

//This delegate can be used to point to methods
//which return void and take a string.
public delegate void MyEventHandler(string foo);

//This event can cause any method which conforms
//to MyEventHandler to be called.
public event MyEventHandler SomethingHappened;

//Here is some code I want to be executed
//when SomethingHappened fires.
void HandleSomethingHappened(string foo)
{
    //Do some stuff
}

//I am creating a delegate (pointer) to HandleSomethingHappened
//and adding it to SomethingHappened's list of "Event Handlers".
myObj.SomethingHappened += new MyEventHandler(HandleSomethingHappened);

//To raise the event within a method.
MyEventHandler("bar");

(* Dies ist der Schlüssel zu Ereignissen in .NET und entfernt die "Magie" - ein Ereignis ist wirklich, unter der Decke, nur eine Liste von Methoden der gleichen "Form". Die Liste wird dort gespeichert, wo das Ereignis lebt Das Ereignis ist "ausgelöst", es ist wirklich nur "gehen Sie durch diese Liste von Methoden und rufen Sie jedes, mit diesen Werten als Parameter." Zuweisen eines Ereignishandlers ist nur ein schöner, einfacher Weg, Ihre Methode zu dieser Liste von Methoden hinzuzufügen heißen).





event-handling