2009-01-25 10 views
4

Je comprends que l'on peut déclencher un événement dans la classe que la déclaration de mise en œuvre se produit, mais je tiens à soulever l'événement au niveau de la classe de base et ont l'événement de la classe dérivée ressusciteront:événement de collecte de la classe de base

public interface IFoo 
{ 
    event EventHandler<FooEventArgs> FooValueChanged; 
    void RaiseFooValueChanged(IFooView sender, FooEventArgs e); 
} 

[TypeDescriptionProvider(typeof(FooBaseImplementor))] 
public abstract class FooBase : Control, IFoo 
{ 
    public virtual event EventHandler<FooEventArgs> FooValueChanged; 

    public void RaiseFooValueChanged(IFooView sender, FooEventArgs e) 
    { 
     FooValueChanged(sender, e); 
    } 
} 

Je ne peux pas avoir le résumé d'événement FooValueChanged, car la classe de base ne peut pas déclencher l'événement. Le code actuel s'exécute, mais l'appel FooValueChanged (expéditeur, e) renvoie une exception NullReferenceException car il n'appelle pas l'événement de la classe dérivée, uniquement celui de la classe de base.

Où est-ce que je me trompe?

Je peux avoir l'événement et l'élévateur à la fois abstrait, mais alors je dois me rappeler d'appeler FooValueChanged (expéditeur, e) dans chaque classe dérivée. J'essaie d'éviter cela tout en étant capable d'utiliser le concepteur Visual Studio pour les contrôles dérivés.

+0

Pour toute personne lisant cette question qui est perplexe sur pourquoi j'ai TypeDescriptionProvider: http://www.urbanpotato.net/default.aspx/document/2001 – Llyle

Répondre

10

première note, la déclaration d'événement que vous utilisez est une notation sténographique en C#:

public event EventHandler Event; 
public void RaiseEvent() { 
    this.Event(this, new EventArgs()); 
} 

équivaut à:

private EventHandler backEndStorage; 
public event EventHandler Event { 
    add { this.backEndStorage += value; } 
    remove { this.backEndStorage -= value; } 
} 
public void RaiseEvent() { 
    this.backEndStorage(this, new EventArgs()); 
} 

Où backEndStorage est un délégué à plusieurs acteurs.


Maintenant, vous pouvez réécrire votre code:

public interface IFoo 
{ 
    event EventHandler<FooEventArgs> FooValueChanged; 
    void RaiseFooValueChanged(IFooView sender, FooEventArgs e); 
} 

[TypeDescriptionProvider(typeof(FooBaseImplementor))] 
public abstract class FooBase : Control, IFoo 
{ 
    protected event EventHandler<FooEventArgs> backEndStorage; 
    public event EventHandler<FooEventArgs> FooValueChanged { 
     add { this.backEndStorage += value; } 
     remove { this.backEndStorage -= value; } 
    } 

    public void RaiseFooValueChanged(IFooView sender, FooEventArgs e) 
    { 
     this.backEndStorage(sender, e); 
    } 
} 

public class FooDerived : FooBase { 
    public event EventHandler<FooEventArgs> AnotherFooValueChanged { 
     add { this.backEndStorage += value; } 
     remove { this.backEndStorage -= value; } 
    } 
} 

Alors maintenant, quand les événements sont ajoutés sur la classe dérivée, ils seront effectivement ajoutés à la backEndStorage de la classe de base, permettant ainsi la classe de base appeler les délégués inscrits dans la classe dérivée.

+0

Bonne réponse et presque exactement ce que je recherchais. Je posterai ma solution finale qui utilise votre recommandation. Merci. – Llyle

+0

+1: Très belle et précise explication. –

+0

Notez que basé sur [Fonctions cachées de C#] (http://stackoverflow.com/questions/9033/hidden-features-of-c/9282#9282), vous pouvez faire: 'protected event EventHandler backEndStorage = delegate {}; ' puis ne vérifie pas null. – earlNameless

1

Pourquoi avez-vous besoin d'un événement? Vous ne pouvez pas utiliser une méthode surchargée. La base appelle la méthode overridable, qui est 'interceptée' par la classe dérivée, qui peut alors déclencher un événement?

+0

J'ai editted le code pour montrer le besoin de l'événement. – Llyle

2

Le résultat final:

public interface IFoo 
{ 
    event EventHandler<FooEventArgs> FooValueChanged; 
    void RaiseFooValueChanged(IFooView sender, FooEventArgs e); 
} 

[TypeDescriptionProvider(typeof(FooBaseImplementor))] 
public abstract class FooBase : Control, IFoo 
{ 
    protected event EventHandler<FooEventArgs> backEndStorage; 
    public abstract event EventHandler<FooEventArgs> FooValueChanged; 

    public void RaiseFooValueChanged(IFooView sender, FooEventArgs e) 
    { 
     if (backEndStorage != null) 
      backEndStorage(sender, e); 
    } 
} 

public class FooDerived : FooBase { 
    public override event EventHandler<FooEventArgs> FooValueChanged { 
     add { backEndStorage += value; } 
     remove { backEndStorage -= value; } 
    } 
}