Let\'s pretend I have something like this:
And something like this:
publ
Here is what I have (the code is tested, btw). It is based on the event throttling extension I created a few years ago. I think a good name for it would be Ouroboros. The major thing about it is that opposite to when using Throttle, it starts the work immediately if a cooldown has passed.
public static IObservable CombineVeryLatest(
this IObservable leftSource,
IObservable rightSource,
Func selector)
{
return Observable.Defer(() =>
{
int l = -1, r = -1;
return Observable.CombineLatest(
leftSource.Select(Tuple.Create),
rightSource.Select(Tuple.Create),
(x, y) => new { x, y })
.Where(t => t.x.Item2 != l && t.y.Item2 != r)
.Do(t => { l = t.x.Item2; r = t.y.Item2; })
.Select(t => selector(t.x.Item1, t.y.Item1));
});
}
public static IObservable WorkSequencer(
this IObservable source, Func> work)
{
return source.Publish(src =>
{
var fire = new Subject();
var fireCompleted = fire.SelectMany(x => work()).Publish();
fireCompleted.Connect();
var whenCanFire = fireCompleted.StartWith(default(TWork));
var subscription = src
.CombineVeryLatest(whenCanFire, (x, flag) => x)
.Subscribe(fire);
return fireCompleted.Finally(subscription.Dispose);
});
}
Then usage would be:
private int _counter;
public MainWindow()
{
InitializeComponent();
var clicks = Observable
.FromEventPattern(TestBn, "Click")
.Do(_ =>
{
Console.WriteLine("click");
_counter++;
});
clicks.WorkSequencer(DoWork).Subscribe();
}
private async Task DoWork()
{
var workNumber = _counter;
Console.WriteLine("Work Start " + workNumber);
await Task.WhenAll(Task.Delay(_counter*100), Task.Delay(1000));
Console.WriteLine("Work Done " + workNumber);
return _counter;
}