0

I am refactoring some code.

Can someone tell me why does my binding in the viewModel stop updating if I comment out those two lines:

.SubscribeOn(ThreadPoolScheduler.Instance)
.ObserveOn(Application.Current.Dispatcher)

How come it affect the second subscribe?

RendererService.WhenRenderProgress.Subscribe

My goal is to remove the wrapper Observable.Create(observer... but when I comment it out, even if the subject emit values, the viewModel does not render them.

Thank you!

public class RendererService
{
    public Subject<int> WhenRenderProgress = new Subject<int>();
    public void Render()
    {
        Observable.Create<Unit>(observer =>
        {
            for (var i = 0; i < 100; i++)
            {
                WhenRenderProgress.OnNext(i);
            }
            observer.OnCompleted();
            return Disposable.Empty;
        })
        .SubscribeOn(ThreadPoolScheduler.Instance)
        .ObserveOn(Application.Current.Dispatcher)
        .Subscribe();
    }
}

public class ViewModel: Screen, IViewModel, IDisposable
{
    public int Progress { get; set; } 
    public ViewModel(RendererService RendererService)
    {
        RendererService.WhenRenderProgress.Subscribe(i =>
        {
            Progress = i;
            NotifyOfPropertyChange(() => Progress);
        });
    }
}
Tom Sawyer
  • 835
  • 2
  • 10
  • 32

1 Answers1

0

EDIT:

Sorry, your comments make sense. It is due to WPF threading requirements. The second subscribe has to happen on the UI thread. The best way for that to happen is to change this line...

    RendererService.WhenRenderProgress.Subscribe(i =>

to this...

    RendererService.WhenRenderProgress.ObserveOn(Application.Current.Dispatcher).Subscribe(i =>

Once you make that change, you can remove the SubscribeOn and ObserveOn calls by the first subscription.

All this happens because Reactive IObservables don't care which thread they're observed on. If your event starts on a background thread, and all the operators are synchronous (which they are here), then it will be observed on the same thread.


The way you have it laid out, this is impossible to reproduce.

If I had to guess, I would guess that there's some exception being thrown in the .Render function, that blows up the first subscription. Since there's no other subscription, the rest of the Observable.Create never happens, since observables only do stuff when there is at least one subscription. The second subscription isn't subscribed to the producing observable, it's listening to a side-effect.

I would recommend you try changing the first subscription call from

    .Subscribe();

to

    .Subscribe(item => {}, e => LogException(e));

or something like that. This way you can see what's going wrong.

Shlomo
  • 14,102
  • 3
  • 28
  • 43
  • I put a breakpoint, both scenario hit the NotifyOfPropertyChange(() => Progress); It just one scenario update the UI while the other one does not update the UI. – Tom Sawyer Apr 26 '18 at 22:33
  • I was wondering if there is something related to the UI thread VS background thread. I do not master WPF enought. – Tom Sawyer Apr 26 '18 at 22:34
  • Yes. Updated answer. – Shlomo Apr 27 '18 at 14:41
  • Hum ... surprise, after removing SubscribeOn and ObserveOn from the first subscribe then adding .ObserveOn(Application.Current.Dispatcher) on the second subscribe, my breakpoint in the second subscribe stop to hit while my breakpoint on the OnNext(i) hit – Tom Sawyer Apr 27 '18 at 17:01
  • Hum ... the code I refactor is in a huge async function. Does this impact Reactive.NET behavior? – Tom Sawyer Apr 27 '18 at 17:22
  • I refactor the code so I can test without the async. As soon that I put .ObserveOn(Application.Current.Dispatcher) on the subscribe who display the data, I break point stop being hit. Is that mean the subject that emit is on another thread? – Tom Sawyer Apr 27 '18 at 19:07