Comment : déclencher les événements de la classe de base dans les classes dérivées (Guide de programmation C#)

L'exemple simple suivant illustre la méthode standard pour déclarer des événements dans une classe de base afin qu'ils puissent également être déclenchés à partir de classes dérivées.Ce modèle est largement utilisé dans les classes Windows Forms de la bibliothèque de classes .NET Framework.

Lors de la création d'une classe pouvant être utilisée comme classe de base pour d'autres classes, vous devez tenir compte du fait que les événements constituent un type particulier de délégués, ne pouvant être appelés qu'à partir de la classe qui les a déclarés.Les classes dérivées ne peuvent pas appeler directement les événements déclarés dans la classe de base.Même si, quelquefois, vous pouvez souhaiter qu'un événement ne puisse être déclenché que par la classe de base, dans la plupart des cas, vous devez permettre à la classe dérivée d'appeler les événements de la classe de base.À cette fin, vous pouvez créer une méthode d'appel protégée dans la classe de base qui encapsule l'événement.En appelant ou en remplaçant cette méthode d'appel, les classes dérivées peuvent appeler indirectement l'événement.

[!REMARQUE]

Ne déclarez pas des événements virtuels dans une classe de base et ne les substituez pas dans une classe dérivée.Le compilateur c# ne gère pas correctement et il est impossible de prédire si un abonné à l'événement dérivé s'abonnera effectivement à l'événement de classe de base.

Exemple


namespace BaseClassEvents
{
    using System;
    using System.Collections.Generic;

    // Special EventArgs class to hold info about Shapes.
    public class ShapeEventArgs : EventArgs
    {
        private double newArea;

        public ShapeEventArgs(double d)
        {
            newArea = d;
        }
        public double NewArea
        {
            get { return newArea; }
        }
    }

    // Base class event publisher
    public abstract class Shape
    {
        protected double area;

        public double Area
        {
            get { return area; }
            set { area = value; }
        }
        // The event. Note that by using the generic EventHandler<T> event type
        // we do not need to declare a separate delegate type.
        public event EventHandler<ShapeEventArgs> ShapeChanged;

        public abstract void Draw();

        //The event-invoking method that derived classes can override.
        protected virtual void OnShapeChanged(ShapeEventArgs e)
        {
            // Make a temporary copy of the event to avoid possibility of
            // a race condition if the last subscriber unsubscribes
            // immediately after the null check and before the event is raised.
            EventHandler<ShapeEventArgs> handler = ShapeChanged;
            if (handler != null)
            {
                handler(this, e);
            }
        }
    }

    public class Circle : Shape
    {
        private double radius;
        public Circle(double d)
        {
            radius = d;
            area = 3.14 * radius * radius;
        }
        public void Update(double d)
        {
            radius = d;
            area = 3.14 * radius * radius;
            OnShapeChanged(new ShapeEventArgs(area));
        }
        protected override void OnShapeChanged(ShapeEventArgs e)
        {
            // Do any circle-specific processing here.

            // Call the base class event invocation method.
            base.OnShapeChanged(e);
        }
        public override void Draw()
        {
            Console.WriteLine("Drawing a circle");
        }
    }

    public class Rectangle : Shape
    {
        private double length;
        private double width;
        public Rectangle(double length, double width)
        {
            this.length = length;
            this.width = width;
            area = length * width;
        }
        public void Update(double length, double width)
        {
            this.length = length;
            this.width = width;
            area = length * width;
            OnShapeChanged(new ShapeEventArgs(area));
        }
        protected override void OnShapeChanged(ShapeEventArgs e)
        {
            // Do any rectangle-specific processing here.

            // Call the base class event invocation method.
            base.OnShapeChanged(e);
        }
        public override void Draw()
        {
            Console.WriteLine("Drawing a rectangle");
        }

    }

    // Represents the surface on which the shapes are drawn
    // Subscribes to shape events so that it knows
    // when to redraw a shape.
    public class ShapeContainer
    {
        List<Shape> _list;

        public ShapeContainer()
        {
            _list = new List<Shape>();
        }

        public void AddShape(Shape s)
        {
            _list.Add(s);
            // Subscribe to the base class event.
            s.ShapeChanged += HandleShapeChanged;
        }

        // ...Other methods to draw, resize, etc.

        private void HandleShapeChanged(object sender, ShapeEventArgs e)
        {
            Shape s = (Shape)sender;

            // Diagnostic message for demonstration purposes.
            Console.WriteLine("Received event. Shape area is now {0}", e.NewArea);

            // Redraw the shape here.
            s.Draw();
        }
    }

    class Test
    {

        static void Main(string[] args)
        {
            //Create the event publishers and subscriber
            Circle c1 = new Circle(54);
            Rectangle r1 = new Rectangle(12, 9);
            ShapeContainer sc = new ShapeContainer();

            // Add the shapes to the container.
            sc.AddShape(c1);
            sc.AddShape(r1);

            // Cause some events to be raised.
            c1.Update(57);
            r1.Update(7, 7);

            // Keep the console window open in debug mode.
            System.Console.WriteLine("Press any key to exit.");
            System.Console.ReadKey();
        }
    }
}
/* Output:
        Received event. Shape area is now 10201.86
        Drawing a circle
        Received event. Shape area is now 49
        Drawing a rectangle
 */

Voir aussi

Référence

Événements (Guide de programmation C#)

Délégués (guide de programmation C#)

Modificateurs d'accès (Guide de programmation C#)

Concepts

Guide de programmation C#

Autres ressources

Création de gestionnaires d'événements dans les Windows Forms