Blocking issue with Rx.NET Subject<T>

Viewed 116

In a WPF application, I am using Observable.Throttle() to limit the frequency of handling certain events coming in from the user interface.

This is the minimal simplified code as it pertains to the usage of Rx:

using System.Reactive.Linq;
using System.Reactive.Subjects;

public class UIEvent
{
    public UIEvent(string name)
    {
        this.Name = name;
    }

    public string Name { get; }
}

public class ViewModel
{
    private ISubject<UIEvent> subject = new Subject<UIEvent>();

    // IEventAggregator is from Caliburn.Micro, but that should not be relevant here.
    public ViewModel(IEventAggregator eventAggregator)
    {
        this.subject
            .Throttle(TimeSpan.FromMilliseconds(500))
            .Subscribe(eventAggregator.Publish);
    }

    // This is called from several places in the associated view
    public RaiseUiEvent(string name)
    {
        this.subject.OnNext(new UIEvent(name));
    }
}

This generally works well and solves the race issue we had before. However, at some point, and even with a low frequency of events coming in, this will lock up in subject.OnNext(). Pausing in Visual Studio at that point shows the following relevant call stack:

WindowsBase.dll!System.Windows.Threading.DispatcherSynchronizationContext.Wait(System.IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
[Native to Managed Transition]      Annotated Frame
[Managed to Native Transition]      Annotated Frame
System.Reactive.Linq.dll!System.Reactive.Linq.ObservableImpl.Throttle<UIEVent>._.OnNext(UIEvent value)
ViewModel.RaiseUiEvent(string name)

I assume/hope the root cause is my very naive/inexperienced use of Rx. I tried synchronizing the subject, which I remember helped me with an issue in a different place, but that didn't change anything about the behavior here. I also experimented with SubscribeOn()/ObserveOn(), but with no real plan or luck.

Am I using the subject wrong? Should I be using a different subject type? Should I be using a subject at all? (Directly attaching to the events in the view via Rx and merging the streams does not seem feasible because of the complexity of the real-world code.)

Thanks for any pointers!

0 Answers
Related