Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

grouping events in C#

Tags:

c#

events

Is there any ready to use solution to group events?

Say I have two events: A and B. I want a Method M to be executed when A and B have been fired, they do not need to fire exactly at the same time.

Something like: Group event G fires after both, A and B have fired. I need to register Method M only at Group event G.

A can fire more than one time, G will only fire after B has fired. Same other way.

I'm looking for a library, which has these events.

Edit: Example

Events:
    A | B | G
1   F   0   0
2   0   F   F
3   0   F   0 
4   0   F   0 
5   0   F   0 
6   F   0   F
7   F   0   0
8   0   F   F
9   0   0   0 
10  F   F   F

F means the event fires, 0 it does not.

like image 418
clx Avatar asked May 21 '13 22:05

clx


3 Answers

You can use Reactive Extensions.

Look at the Observable.FromEvent (or Observable.FromEventPattern) method to convert standard .NET event to observable and then you can group the results using Observable.CombineLatest.

Here is a pseudo code:

var observableA = Observable.FromEvent(yourEventA);
var observableB = Observable.FromEvent(yourEventB);

var observableG = observableA.CombineLatest(observableB, ...)

The generated observable is triggered when both events are triggered.

EDIT

CombineLatest produce an output with the latest results, without resetting its state. So for example if A1 is fired then B1 is fired G1 is produced with (A1 + B1), but if B2 is fired then G2 is produced with (A1 + B2) and so on...

To exactly produce your expected results you can write something like:

    private void SetupEvents()
    {
        var observableA = Observable.FromEventPattern((e) => btA.Click += e, (e) => btA.Click -= e);
        var observableB = Observable.FromEventPattern((e) => btB.Click += e, (e) => btB.Click -= e);

        EventPattern<object> lastA = null;
        EventPattern<object> lastB = null;
        var observableG = observableA.CombineLatest(observableB, (rA, rB) =>
        {
            if (lastA == rA || lastB == rB)
                return null;

            lastA = rA;
            lastB = rB;
            return new Tuple<EventPattern<object>, EventPattern<object>>(rA, rB);
        }).Where(p => p != null);

        observableG.Subscribe(r => Trace.WriteLine("A + B"));

        // or use ToEvent to generate another standard .NET event
        //observableG.ToEvent().OnNext += GEvent;
    }

    //void GEvent(System.Reactive.EventPattern<object> obj)
    //{
    //    Trace.WriteLine("A + B");
    //}

Basically I check if the latest results are different from the current result. Maybe there is some native RX extension for your case but I cannot find it.

like image 178
Davide Icardi Avatar answered Oct 12 '22 18:10

Davide Icardi


I think that Reactive Extensions is probably closest to what you are looking for. It provides helpers to turn events into observables, and a linq-style syntax that you can use to compose those observables.

like image 24
spender Avatar answered Oct 12 '22 17:10

spender


You can write such a class yourself. Here's a (very) trivial implementation:

public class TwoEventGroup
{
   private bool _eventAFired;
   private bool _eventBFired;

   public void EventAHandler()
   {
      _eventAFired = true;
      TestAndFire();
   }

   public void EventBHandler()
   {
      _eventBFired = true;
      TestAndFire();
   }

   private void TestAndFire()
   {
      if (_eventAFired && _eventBFired)
      {
         _eventAFired = false;
         _eventBFired = false;
         if (GroupEvent != null)
           GroupEvent();
      }
   }

   public event Action GroupEvent;
}

This is just a conceptual implementation, you'd probably want to have the event delegate as a generic, extend it to n events instead of just two, (maybe) deal with time outs between event firing, thinking about how this class will be extended (if at all), etc.

@spender suggestion of Rx is worthwhile (+1) but the library is geared towards asynchronous events and has a somewhat steep learning curve. It might be overkill if you just want simple groupings of known events, or events of the same type and not something entirely generic.

like image 30
Eli Algranti Avatar answered Oct 12 '22 18:10

Eli Algranti