Sunday, July 19, 2015

C# complete operation event handler

Introduction



Fig.1 - Event handling (normal behavior)
Usually when we want to listen an event we have to connect an event handler and then we'll receive calls to the event handler each time the event is raised from the originating source (Fig.1).

In some other scenarios we need to be informed if an event occurred event if its already sent (Fig.2).


Fig. 2 - Listen to past events

Follow is an example :

using System;

namespace MyApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Test x = new Test();           

            x.Fire();

            x.EvTest += (a, b) =>
            {
                Console.WriteLine("Event fired");
            };
        }
    }

    public class Test
    {

        public event EventHandler EvTest;

        public void Fire()
        {
            if (EvTest != null) EvTest(this, null);
        }

    }
}

Running the above code you'll notice that the event is not intercepted because the handler is connected only after the event occurred.

Lib0.Core.EventOperation

To get rid of this problem I built a class to manage such events, called EventOperation.

Source code

Source code for this library is located at follow url https://github.com/devel0/Lib0

Example

/// <summary>
/// Be notified after the event fired.
/// </summary>
[TestMethod]
public void Test4()
{
  IEventOperation op = new EventOperation(EventOperationBehaviorTypes.RemindPastEvents);

  op.Fire();

  Assert.IsTrue(op.FireCount == 1);
  Assert.IsTrue(op.HandledCount == 0);

  op.Event += (a, b) => { }; // This handler function is called right here
                             // cause previous event already fired.
  Assert.IsTrue(op.FireCount == 1);
  Assert.IsTrue(op.HandledCount == 1);
}

EventOperation takes an optional argument to set which behavior between "Normal" or "RemindPastEvent" types.

Multiple listeners

Follow unit test demonstrate how the event operation works using "RemindPastEvent" behavior and multiple listeners :

/// <summary>
/// Be notified after the event fired (multiple listeners).
/// </summary>
[TestMethod]
public void Test5()
{
    IEventOperation op = new EventOperation(EventOperationBehaviorTypes.RemindPastEvents);

    var listener1HitCount = 0;
    var listener2HitCount = 0;

    {
        op.Fire(); // event fired ( no handlers yet connected )
        Assert.IsTrue(op.FireCount == 1 && op.HandledCount == 0);

        op.Event += (a, b) => // listener1 connects and receive 1 event
        {
            ++listener1HitCount;
        };
        Assert.IsTrue(op.FireCount == 1 && op.HandledCount == 1);
    }

    {
        op.Fire(); // event fired ( listener1 will receive its 2-th event )
        Assert.IsTrue(op.FireCount == 2 && op.HandledCount == 2);

        op.Event += (a, b) => // listener2 connected and receive 2 events
        {
            ++listener2HitCount;
        };                
    }

    Assert.IsTrue(listener1HitCount == 2 && listener2HitCount == 2);
    Assert.IsTrue(op.FireCount == 2 && op.HandledCount == listener1HitCount + listener2HitCount);            
}

A final word

RemindPastEvents behavior implies that a list of past event arguments are stored into the memory, so be aware not to use it for massive event handling. The scenario in which this class make sense can be for example the one represented in Fig2 when you need to synchronize many listeners to an event that we don't know if its already fired.


Creative Commons License
C# complete operation event handler by Lorenzo Delana is licensed under a Creative Commons Attribution 4.0 International License.

No comments:

Post a Comment