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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With