C#Foundation - Events

Posted by dilum on Fri, 12 Jun 2020 03:35:53 +0200

Preface

In this chapter, I mainly use this series of C# basic chapters to sort out the past learning notes, summarize and summarize them, and to understand them more thoroughly.

In the previous article, we learned more about delegation, which is equivalent to using a method as another method parameter, and can also be used as a bridge between two methods that cannot be invoked directly.

Let's review the delegation example below.

    public delegate void ExecutingDelegate(string name);

    public class ExecutingManager
    {
        public void ExecuteProgram(string name, ExecutingDelegate ToExecuting)
        {
            ToExecuting(name);
        }
    }
    private static void StartExecute(string name)
    {
        Console.WriteLine("Start execution:" + name);
    }

    private static void EndExecute(string name)
    {
        Console.WriteLine("End execution:" + name);
    }

    static void Main(string[] args)
    {
        ExecutingManager exec = new ExecutingManager();
        exec.ExecuteProgram("Start.", StartExecute);
        exec.ExecuteProgram("End...", EndExecute);
        Console.ReadKey();
    }

Based on the example above, and using the knowledge learned in the previous section, what can I do to bind multiple methods to the same delegate variable for multicasting?

Modify the code again:

    static void Main(string[] args)
    {
        ExecutingManager exec = new ExecutingManager();
        ExecutingDelegate executingDelegate;
        executingDelegate = StartExecute;
        executingDelegate += EndExecute;
        exec.ExecuteProgram("yuan", executingDelegate);

        Console.ReadKey();
    }

However, at this point, we find that it is possible to encapsulate variables of the instantiation declaration delegate into the ExecutingManager class, which makes it easier to invoke?

    public class ExecutingManager
    {
        /// <summary>
        ///Declare the executingDelegate variable inside the ExecutingManager class
        /// </summary>
        public ExecutingDelegate executingDelegate;
        public void ExecuteProgram(string name, ExecutingDelegate ToExecuting)
        {
            ToExecuting(name);
        }
    }
    static void Main(string[] args)
    {
        ExecutingManager exec = new ExecutingManager();
        exec.executingDelegate = StartExecute;
        exec.executingDelegate += EndExecute;
        exec.ExecuteProgram("yuan", exec.executingDelegate);
        Console.ReadKey();
    }

There's nothing wrong with this, but we found this statement strange.In callExec.ExecuteProgramThe executingDelegate field of the exec is passed in again when the method is used, so why not modify the ExecutingManager class so that:

    public class ExecutingManager
    {
        /// <summary>
        ///Declare the delegate1 variable inside the GreetingManager class
        /// </summary>
        public ExecutingDelegate executingDelegate;
        public void ExecuteProgram(string name)
        {
            if (executingDelegate != null) // If there is a way to register delegate variables
            {
                executingDelegate(name); // Calling methods through delegates
            }
        }
    }
    static void Main(string[] args)
    {
        ExecutingManager exec = new ExecutingManager();
        exec.executingDelegate = StartExecute;
        exec.executingDelegate += EndExecute;
        exec.ExecuteProgram("yuan");
        Console.ReadKey();
    }

Looking at it this way, it's much simpler to call it once.

text

In our daily life, we may encounter such a variety of things, and for these things we will take appropriate measures.For example, when you want to give a goddess a birthday, you can give her gifts.In this case, in C# development, birthdays are treated as events, and gift-giving is the response of events.

When the Goddess has her birthday, the Goddess will post a birthday event, and you will be notified of it and respond to it (gifting, etc.).The object that triggers this event can be called the event publisher, and the event subscriber who captures and handles it accordingly can be seen that the goddess acts as the publisher and you act as the subscriber yourself.

There are two types of roles that are derived from birthdays, event publisher and event subscriber.

start

1. Publisher/Subscriber Mode

In development, do we encounter a scenario where when a particular program event occurs, other parts of the program can be notified that the event is registered to occur?

The publisher defines a series of events and provides a registration method; the subscriber registers with the publisher and provides a callback method, event handler; when an event is triggered, the subscriber is notified and all methods submitted by the subscriber are executed.

  • Publisher: The class or structure that publishes an event, and other classes can be notified when the event occurs.
  • Subscriber: A class or structure that is registered and notified when an event occurs.
  • Event handler: A method registered by a subscriber to an event and executed when the publisher triggers the event.Event handler methods can be defined in the class or result in which the event is located or in different classes or structures.
  • Trigger Event: Terminology for calling an event.When an event triggers, all methods registered with it are called once.

2. Basic Use

        /// <summary>
        ///Customize a delegate first
        /// </summary>
        /// <param name="oldPrice"></param>
        /// <param name="newPrice"></param>
        public delegate void PriceChangedHandler(decimal oldPrice, decimal newPrice);
        /// <summary>
        ///This publisher
        /// </summary>
        public class IPhone
        {
            decimal price;
            /// <summary>
            ///Define an event
            /// event used to define events
            /// PriceChangedHandler delegate type, event needs to call method required by subscriber through delegate
            /// </summary>
            public event PriceChangedHandler PriceChanged;
          
            public decimal Price
            {
                get { return price; }
                set
                {
                    if (price == value)
                        return;
                    decimal oldPrice = price;
                    price = value;             // Triggers if the call list is not empty.            
                    if (PriceChanged != null)   //Used to determine if events have been registered by subscribers
                        PriceChanged(oldPrice, price);   //Call Event
                }
            }
        }
        /// <summary>
        ///This one subscriber
        /// </summary>
        /// <param name="oldPrice"></param>
        /// <param name="price"></param>
        static void iPhone_PriceChanged(decimal oldPrice, decimal price)
        {
            Console.WriteLine("618 Promotions, full-range mobile only " + price + " Yuan, original price " + oldPrice + " Yuan, come and grab it!");
        }
        static void Main()
        {
            ///Instantiate a publisher class
            IPhone phone = new IPhone()
            {
                Price = 5288
            };         // Subscription Events   
            phone.PriceChanged += iPhone_PriceChanged;          //Registration Adjustment Price for Completion Event (Event Occurs)    
            phone.Price = 3999;                                //Fires an event and invokes it
            Console.ReadKey();
        }

Output:

618 promotional activities, the entire mobile phone only sold 3999 yuan, the original price 5288 yuan, come and grab!

3. Resolution

  1. Delegate type declaration: Events and event handlers must have a common signature and return type, which are described by the delegate type.
  2. Event declaration: Use the keyword evet to declare an event, which is called a published event when the declared event is a public.
  3. Event Registration: Subscribers register events with the +=operator and provide an event handler.
  4. Event handler: A method registered by a subscriber to an event that can display named methods, anonymous methods, or Lambda expressions
  5. Trigger Event: Code used by the publisher to invoke the event

4. Grammar

The declarative syntax for events:

//Declare an event
public [static] event EventHandler EventName;
//Declare multiple events of the same type
public [static] event EventHandler EventName1, EventName2, EventName3;

Events must be declared in a class or structure because an event is not a type, it is a member of a class or structure.

Before an event is triggered, you can compare it with null to determine if an event registration handler is included.Because event members are initialized, null is the default.

The delegate type EventHandler is a delegate that declares an event-specific use.Events provide structured access to delegates; that is, delegates in events cannot be accessed directly.

5. Usage

View source code:

The standard pattern for events is the EventHandler delegate type declared under the System namespace.

EventArgs is a class under System as follows:

using System.Runtime.InteropServices;

namespace System
{
    [Serializable]
    [ComVisible(true)]
    [__DynamicallyInvokable]
    public class EventArgs
    {
        [__DynamicallyInvokable]
        public static readonly EventArgs Empty = new EventArgs();

        [__DynamicallyInvokable]
        public EventArgs()
        {
        }
    }
}

According to the EventArgs source code, EventArgs itself cannot save and transfer data.

If you want to save and transfer data, you can implement a derived class of EventArgs, then define related fields to save and pass parameters.

    public class IPhone
    {
        decimal price;
        /// <summary>
        ///Define an event using EventHandler
        /// </summary>
        public event EventHandler PriceChanged;
        protected virtual void OnPriceChanged()
        {
            if (PriceChanged != null)
                PriceChanged(this, null);
        }
        public decimal Price
        {
            get { return price; }
            set
            {
                if (price == value) return;
                decimal oldPrice = price; 
                price = value;             // Triggers if the call list is not empty.      
                if (PriceChanged != null)  // //Used to determine if events have been registered by subscribers
                    OnPriceChanged();
            }
        }
    }
    /// <summary>
    ///This one subscriber
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    static void iphone_PriceChanged(object sender, EventArgs e)
    {
        Console.WriteLine("Year-end sales, come and grab!");
    }
    static void Main()
    {
        IPhone phone = new IPhone()
        {
            Price = 5288M
        };         // Subscription Events  
        phone.PriceChanged += iphone_PriceChanged;
        // Adjust Price (Event Occurs)   
        phone.Price = 3999;
        Console.ReadKey();
    }

Transfer data by extending EventHanlder

There are also generic EventHandler classes under System.From this point on, we can pass a class derived from EventArgs as a type parameter so that we can get the data that the derived class holds.

    ///Extension Class
    public class PriceChangedEventArgs : System.EventArgs
    {
        public readonly decimal OldPrice;
        public readonly decimal NewPrice;
        public PriceChangedEventArgs(decimal oldPrice, decimal newPrice)
        {
            OldPrice = oldPrice;
            NewPrice = newPrice;
        }
    }
    public class IPhone
    {
        decimal price;
        public event EventHandler<PriceChangedEventArgs> PriceChanged;
        protected virtual void OnPriceChanged(PriceChangedEventArgs e)
        {
            if (PriceChanged != null)
                PriceChanged(this, e);
        }
        public decimal Price
        {
            get { return price; }
            set
            {
                if (price == value) return;
                decimal oldPrice = price;
                price = value;             // Triggers if the call list is not empty.      
                if (PriceChanged != null)
                    OnPriceChanged(new PriceChangedEventArgs(oldPrice, price));
            }
        }
    }
    static void iphone_PriceChanged(object sender, PriceChangedEventArgs e)
    {
        Console.WriteLine("618 Promotions, full-range mobile only " + e.NewPrice + " Yuan, original price " + e.OldPrice + " Yuan, come and grab it!");
    }
    static void Main()
    {
        IPhone phone = new IPhone()
        {
            Price = 5288M
        };         // Subscription Events  
        phone.PriceChanged += iphone_PriceChanged;
        // Adjust Price (Event Occurs)   
        phone.Price = 3999;
        Console.ReadKey();
    }

output

618 promotional activities, the entire mobile phone only sold 3999 yuan, the original price 5288 yuan, come and grab!

6. Remove Events

The -=operator handler can be used to remove an event from it, and when the program is finished, it can be removed from it.

        class Publiser
        {
            public event EventHandler SimpleEvent;

            public void RaiseTheEvent()
            {
                SimpleEvent(this, null);
            }
        }

        class Subscriber
        {
            public void MethodA(object o, EventArgs e) { Console.WriteLine("A"); }
            public void MethodB(object o, EventArgs e) { Console.WriteLine("B"); }
        }


        static void Main(string[] args)
        {
            Publiser p = new Publiser();
            Subscriber s = new Subscriber();

            p.SimpleEvent += s.MethodA;
            p.SimpleEvent += s.MethodB;
            p.RaiseTheEvent();

            Console.WriteLine("\n remove B Event Handler");
            p.SimpleEvent -= s.MethodB;
            p.RaiseTheEvent();

            Console.ReadKey();
        }

Output:

7. Event Accessors

Operator+=, -=The only operator allowed for events.These operators are predefined behaviors.However, we can modify the behavior of these operators so that events execute any code we want to define.

You can control the behavior of event operators +=, -= by defining event accessors for events

  1. Two accessors: add and remove
  2. Accessors that declare events look similar to declaring a familiar one.

The following example demonstrates a declaration with an accessor. Both accessors have an implicit value parameter called value that accepts references to instances or static methods

public event EventHandler Elapsed
{
    add
    {
        //... code that executes the +=operator
    }

     remove
     {
        //... code that executes the -=operator
     }

}

Events do not contain any embedded delegate objects when event accessors are declared. We must implement our own mechanisms for storing and removing events.

Event accessors are represented as void methods, that is, return statements that return values cannot be used.

Example:

        //Declare a delegate
        delegate void EventHandler();

        class MyClass
        {
            //Declare a member variable to hold the event handle (delegate called when the event is fired)
            private EventHandler m_Handler = null;

            //Fire event
            public void FireAEvent()
            {
                if (m_Handler != null)
                {
                    m_Handler();
                }
            }

            //Declare Events
            public event EventHandler AEvent
            {
                //Add Accessor
                add
                {
                    //Notice that the accessor actually contains an implicit parameter named value
                    //The value of this parameter is the delegate passed in when += is called for the client program
                    Console.WriteLine("AEvent add Called,value Of HashCode by:" + value.GetHashCode());
                    if (value != null)
                    {
                        //Set m_Handler field saves new handler
                        m_Handler = value;
                    }
                }

                //Delete Accessors
                remove
                {
                    Console.WriteLine("AEvent remove Called,value Of HashCode by:" + value.GetHashCode());
                    if (value == m_Handler)
                    {
                        //Set m_Handler is null, the event will no longer be fired
                        m_Handler = null;
                    }
                }

            }

        }

        static void Main(string[] args)
        {
            MyClass obj = new MyClass();
            //Create delegation
            EventHandler MyHandler = new EventHandler(MyEventHandler);
            MyHandler += MyEventHandle2;
            //Register delegates to events
            obj.AEvent += MyHandler;
            //Fire event
            obj.FireAEvent();
            //Revoke delegation from event
            obj.AEvent -= MyHandler;
            //Refire Event
            obj.FireAEvent();


            Console.ReadKey();
        }
        //Event Handler
        static void MyEventHandler()
        {
            Console.WriteLine("This is a Event!");
        }

        //Event Handler
        static void MyEventHandle2()
        {
            Console.WriteLine("This is a Event2!");
        }

Output:

summary

  1. This section describes the basic use of events, as well as the standard grammar of events, event accessors, and many other places to get a general understanding and grasp of the basic use of events.
  2. Combination Previous The delegation of and events in this section, delegation and events, we have a general grasp of the basic usage.And put it into practice, combined with actual development, and apply it.
  3. If there are any mistakes or incomprehensions, I hope you can make more corrections, ask questions, discuss them together, keep learning and make progress together.

Reference resources File C#Illustration Tutorial

Note: Search Focus on Public Number [DotNet Valley]--Reply to [C#Illustration], available C#Illustration Tutorial file

Topics: C# Mobile Lambda