Zurb
Zurb

Reputation: 738

Wait until same event has happened for a timespan using Rx

Using Reactive.NET, how can I wait until the same event has happened for n seconds before performing an action?

The following sample (C#, WinForms) is doing what I want, but I want a delay (let say 1 second) before the expanding happens:

var autoExpand = Observable.FromEventPattern<DragEventArgs>(tree, "DragOver");

autoExpand
    .ObserveOn(SynchronizationContext.Current)
    .Distinct(dragEvent => tree.GetNodeFromCoordinates(dragEvent.EventArgs.X, dragEvent.EventArgs.Y))
    .Subscribe(dragEvent => {
            TreeNode node = tree.GetNodeFromCoordinates(dragEvent.EventArgs.X, dragEvent.EventArgs.Y);

            if (node != null) node.Expand();
        });

Upvotes: 1

Views: 697

Answers (1)

Alex
Alex

Reputation: 7919

I believe you're looking for Throttle:

var autoExpand = Observable.FromEventPattern<DragEventArgs>(tree, "DragOver");

autoExpand
    .Select(dragEvent => tree.GetNodeFromCoordinates(dragEvent.EventArgs.X, dragEvent.EventArgs.Y))
    .DistinctUntilChanged()
    .Throttle(TimeSpan.FromSeconds(1))
    .ObserveOn(SynchronizationContext.Current)
    .Subscribe(node => {
            if (node != null) node.Expand();
        });

Note:

  • To avoid making tree.GetNodeFromCoordinates() twice, I have used it with the Select operator to bring it through to the subscription
  • Handily, we can use DistinctUntilChanged to block repeated node selection events if the node is the same
  • I have moved the ObserveOn operator to after the Throttle call to avoid blocking the thread - general guidelines for ObserveOn suggest that you should leave it as the last operator before your subscription. If you do need to use SynchronizationContext.Current for tree.GetNodeFromCoordinates() then you might need to switch schedulers a few times to avoid cross-threading exceptions.

Upvotes: 2

Related Questions