0

I have a class that has, among others, the three following events:

  • DataSourceLoaded
  • DataSourceUnloaded
  • DataSourceFieldChanged

Right now I am using RX.Net in combination with its .Throttle()'ing functionality to slow down handling of burst / frequent incoming events as I only need to know IF something changed recently, not every single occurrence is relevant to me.

The part that I have a bit of problems with is that the underlying datasource may be added/removed at any time and the handler of the DataSourceFieldChanged event streams uses the datasource.

So basically the DataSourceFieldChanged event stream should only start once the DataSourceLoaded event occurred, stop immediately once a DataSourceUnloaded event occurred and re-start whenever the DataSourceLoaded reoccurred.. and so on.

After that DataSourceUnloaded event occurred, all 'throttled' DataSourceFieldChanged streams should however not trigger again.. as in: if a DataSourceFieldChanged event occurred and within the 500ms .Throttle() timespan a DataSourceUnloaded event occurred, the DataSourceFieldChanged event stream should not call the handler.

If a(nother) DataSourceLoaded event happens within or outside that previous 500ms DataSourceFieldChanged .Throttle() window also happens, they should also not trigger the DataSourceFieldChanged handler.

Is there any way to bring these three event streams in one combined RX.Net statement?

Moreover & ideally, IF the handler of DataSourceFieldChanged is already running while the DataSourceUnloaded event occurs, is it possible to pass along a CancellationToken into the DataSourceFieldChanged handler that got triggered beforehand and lets me cancel ongoing activities (so that I do not attempt to access the now gone datasource)?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Jörg Battermann
  • 4,044
  • 5
  • 42
  • 79

1 Answers1

2

Assuming that DataSourceLoaded and DataSourceUnloaded events are always raised in pairs:

from _ in DataSourceLoaded
from changed in DataSourceFieldChanged.Throttle(x).TakeUntil(DataSourceUnloaded)
select changed;

Read it as:

  1. For each DataSourceLoaded event,
  2. project throttled DataSourceFieldChanged events,
  3. until a DataSourceUnloaded event.
Dave Sexton
  • 2,562
  • 1
  • 17
  • 26
  • Thanks Dave! And duh.. that was indeed way too easy - thought it would be more complex. One Q regarding cancellation of ongoing subscriptions / methods running for each 'changed' above: how would you signal cancellation whenever a DataSourceUnloaded event occurs WHILE the changed event is still being handled (basically the Q in the last paragraph in my original question)? – Jörg Battermann Oct 30 '14 at 22:42
  • `OnNext` calls in Rx are serialized, so if `DataSourceUnloaded` fires while you're observing a call, then you simply won't receive another call. There's obviously an unavoidable race condition though. According to the Rx contract, it "will make a best effort attempt to stop all outstanding work". See §4.4 in the [Rx Design Guidelines](http://go.microsoft.com/fwlink/?LinkID=205219). – Dave Sexton Oct 31 '14 at 04:01
  • To be clear, the Rx contract that I just quoted means that any subsequent or enqueued calls to `OnNext` will simply _not_ be observed. It doesn't abort the current call to `OnNext` or anything like that. – Dave Sexton Oct 31 '14 at 04:07
  • @JörgB. - it is fairly straight forward to send the observer of the current `DataSourceFieldChanged` a cancellation signal so it can cancel its current work after a `DataSourceUnloaded` event. Pose it as a new SO question if you want to see some solutions. – Brandon Nov 03 '14 at 12:16
  • Oh I see, he meant that the work that's already running in OnNext needs to be cancelled, not the work that's about to run. Agreed, a new Q is more apt since the answer is going to involve either external state or additional operators. – Dave Sexton Nov 03 '14 at 13:13
  • E.g., This `SelectMany` overload seems appropriate, assuming that he needs an Async function: `SelectMany(IObservable source, Func> taskSelector, Func resultSelector)` – Dave Sexton Nov 03 '14 at 13:16
  • @Brandon yes, that's what I originally meant - follow-up question posted here: http://stackoverflow.com/questions/26716527/cancel-rx-net-observers-ongoing-onnext-methods – Jörg Battermann Nov 03 '14 at 14:45