web-dev-qa-db-de.com

C #: ein geerbtes Ereignis auslösen

Ich habe eine Basisklasse, die die folgenden Ereignisse enthält:

public event EventHandler Loading;
public event EventHandler Finished;

In einer Klasse, die von dieser Basisklasse erbt, versuche ich, das Ereignis auszulösen:

this.Loading(this, new EventHandler()); // All we care about is which object is loading.

Ich erhalte folgende Fehlermeldung:

Das Ereignis 'BaseClass.Loading' kann nur auf der linken Seite von + = oder - = (BaseClass ') erscheinen.

Ich gehe davon aus, dass ich auf diese Ereignisse nicht wie andere ererbte Mitglieder zugreifen kann.

133
jwarzech

Was Sie tun müssen, ist folgendes:

Erstellen Sie in Ihrer Basisklasse (in der Sie die Ereignisse deklariert haben) geschützte Methoden, mit denen die Ereignisse ausgelöst werden können:

public class MyClass
{
   public event EventHandler Loading;
   public event EventHandler Finished;

   protected virtual void OnLoading(EventArgs e)
   {
       EventHandler handler = Loading;
       if( handler != null )
       {
           handler(this, e);
       }
   }

   protected virtual void OnFinished(EventArgs e)
   {
       EventHandler handler = Finished;
       if( handler != null )
       {
           handler(this, e);
       }
   }
}

(Beachten Sie, dass Sie diese Methoden wahrscheinlich ändern sollten, um zu prüfen, ob Sie den Eventhandler aufrufen müssen oder nicht).

In Klassen, die von dieser Basisklasse erben, können Sie einfach die OnFinished- oder die OnLoading-Methode aufrufen, um die Ereignisse auszulösen:

public AnotherClass : MyClass
{
    public void DoSomeStuff()
    {
        ...
        OnLoading(EventArgs.Empty);
        ...
        OnFinished(EventArgs.Empty);
    }
}
146

Sie können nur auf ein Ereignis in der deklarierenden Klasse zugreifen, da .NET hinter den Kulissen private Instanzvariablen erstellt, die den Delegaten tatsächlich enthalten. Dies tun..

public event EventHandler MyPropertyChanged;

tut das eigentlich;

private EventHandler myPropertyChangedDelegate;

public event EventHandler MyPropertyChanged
{
    add { myPropertyChangedDelegate += value; }
    remove { myPropertyChangedDelegate -= value; }
}

und das zu tun ...

MyPropertyChanged(this, EventArgs.Empty);

ist eigentlich das ...

myPropertyChangedDelegate(this, EventArgs.Empty);

Sie können also (offensichtlich) nur innerhalb der deklarierenden Klasse auf die Instanzvariable private delegate zugreifen.

Die Konvention sieht so etwas in der deklarierenden Klasse vor.

protected virtual void OnMyPropertyChanged(EventArgs e)
{
    EventHandler invoker = MyPropertyChanged;

    if(invoker != null) invoker(this, e);
}

Sie können dann OnMyPropertyChanged(EventArgs.Empty) von einer beliebigen Stelle in dieser Klasse oder unterhalb der Vererbungshierarchie aufrufen, um das Ereignis aufzurufen.

116
Adam Robinson

Ich gehe davon aus, dass ich auf diese Ereignisse nicht wie andere ererbte Mitglieder zugreifen kann.

Genau. Es ist üblich, für jedes Ereignis in der Basisklasse eine geschützte Funktion OnXyz oder RaiseXyz bereitzustellen, um das Anheben von geerbten Klassen zu ermöglichen. Zum Beispiel:

public event EventHandler Loading;

protected virtual void OnLoading() {
    EventHandler handler = Loading;
    if (handler != null)
        handler(this, EventArgs.Empty);
}

In der geerbten Klasse aufgerufen:

OnLoading();
8
Konrad Rudolph

Du kannst es so versuchen, es funktioniert für mich:

public delegate void MyEventHaldler(object sender, EventArgs e);

public class B
{
    public virtual event MyEventHaldler MyEvent;
    protected override void OnChanged(EventArgs e)
    {
        if (MyEvent != null)
            MyEvent(this, e);
    }
}

public class D : B
{
    public override event MyEventHaldler MyEvent;
    protected override void OnChanged(EventArgs e)
    {
        if (MyEvent != null)
            MyEvent(this, e);
    }
}
0

nicht um einen alten Thread wiederzubeleben, aber falls jemand sucht, was ich getan habe 

protected EventHandler myPropertyChangedDelegate;

public event EventHandler MyPropertyChanged
{
    add { myPropertyChangedDelegate += value; }
    remove { myPropertyChangedDelegate -= value; }
}

Auf diese Weise können Sie das Ereignis in eine abgeleitete Klasse übernehmen, sodass Sie es aufrufen können, ohne die Methode umbrechen zu müssen, während die + = -Syntax beibehalten wird. Ich denke, Sie könnten das noch mit den Umwickelmethoden tun, wenn Sie dies tun würden 

public event EventHandler MyPropertyChanged
{
   add { AddDelegate(value); }
   remove { RemoveDelegate(value); }
}
0
Zeraphil