none
simplify WPF dispatcher calls

    Question

  • Ive got the following code:

    ObservableCollection<ImageView> imagesViews = new ObservableCollection<ImageView>();
    foreach(var image in images)
    {
          Application.Current.Dispatcher.BeginInvoke(new Action(() => imagesViews.Add(CreateImageView(image)), DispatcherPriority.Loaded);
    }
    
    I want to simplify it with reactive.

    Ive tried the following:

    ObservableCollection<ImageView> imagesViews = new ObservableCollection<ImageView>();
    images.ToObservable().ObserveOnDispatcher().Select(image => CreateImageView(image)).Subscribe(imagesViews.Add);
    


    First of all Im not sure this will behave the same as above... secondly i cant set the dispatcherpriority... id like to have something like ... .ObserverOnDispatcher(DispatcherPriority.Loaded). ...

    Suggestions?

    EDIT:

    It would also be nice to have an extensions method like ObserveOnWPFDispatcher since I think ObserverOn(Application.Current.Dispatcher) is quite common
    Sunday, February 21, 2010 10:53 AM

Answers

  • Hi,

    That looks fine, except it would be better to just create an overload for ObserveOnDispatcher that has priority as a parameter (as I mentioned previously).  And also use Invoke instead of BeginInvoke; everything's being dispatched to the same thread, so there's no need to introduce more concurrency.

    - Dave
    http://davesexton.com/blog
    • Marked as answer by Dragon89 Sunday, February 21, 2010 12:50 PM
    Sunday, February 21, 2010 12:44 PM

  • Solution for future reference:

    public static IObservable<T> ObserveOnDispatcher<T>(this IObservable<T> observable, DispatcherPriority priority)
            {
                if (observable == null)
                    throw new NullReferenceException();
    
                return observable.ObserveOn(Dispatcher.CurrentDispatcher, priority);
            }
    
            public static IObservable<T> ObserveOn<T>(this IObservable<T> observable, Dispatcher dispatcher, DispatcherPriority priority)
            {
                if (observable == null)
                    throw new NullReferenceException();
    
                if (dispatcher == null)
                    throw new ArgumentNullException("dispatcher");
    
                return Observable.CreateWithDisposable<T>(o =>
                {
                    return observable.Subscribe(
                        obj => dispatcher.Invoke((Action)(() => o.OnNext(obj)), priority),
                        ex => dispatcher.Invoke((Action)(() => o.OnError(ex)), priority),
                        () => dispatcher.Invoke((Action)(() => o.OnCompleted()), priority));
                });
            }

    • Marked as answer by Dragon89 Sunday, February 21, 2010 1:02 PM
    Sunday, February 21, 2010 1:01 PM

All replies

  • not sure if im doing this right.. but maybe like this?

            public static IObservable<T> ObserveOnWPFDispatcher<T>(this IObservable<T> observable)
            {
                return observable.ObserveOn(Application.Current.Dispatcher);
            }
    
            public static IObservable<T> ObserveOnWPFDispatcher<T>(this IObservable<T> observable, DispatcherPriority priority)
            {
                return Observable.CreateWithDisposable<T>(o =>
                            {
                                return observable.Subscribe(
                                    obj => Application.Current.Dispatcher.BeginInvoke(new Action(() => o.OnNext(obj)), priority),
                                    ex => Application.Current.Dispatcher.BeginInvoke(new Action(() => o.OnError(ex)), priority),
                                    () => Application.Current.Dispatcher.BeginInvoke(new Action(() => o.OnCompleted()), priority));
                            });
            }

    Sunday, February 21, 2010 11:49 AM
  • Hi, 

    Adding an ObserveOnWPFDispatcher method sounds confusing; ObserveOnDispatcher already works with WPF.  Perhaps an overload that accepts priority would be more suitable.  Although, setting the priority is not so common as I understand it, and I think the following code is readable as is anyway.

    var views = from image in images.ToObservable()
                select CreateImageView(image);
    
    var dispatcher = Application.Current.Dispatcher;
    var priority = DispatcherPriority.Loaded;
    
    views.Subscribe(view => dispatcher.Invoke(priority, (Action) (() => imagesViews.Add(view))));


    - Dave

    • Edited by Dave Sexton Sunday, February 21, 2010 12:39 PM Added C# colorization
    Sunday, February 21, 2010 12:39 PM
  • Hi,

    That looks fine, except it would be better to just create an overload for ObserveOnDispatcher that has priority as a parameter (as I mentioned previously).  And also use Invoke instead of BeginInvoke; everything's being dispatched to the same thread, so there's no need to introduce more concurrency.

    - Dave
    http://davesexton.com/blog
    • Marked as answer by Dragon89 Sunday, February 21, 2010 12:50 PM
    Sunday, February 21, 2010 12:44 PM

  • Solution for future reference:

    public static IObservable<T> ObserveOnDispatcher<T>(this IObservable<T> observable, DispatcherPriority priority)
            {
                if (observable == null)
                    throw new NullReferenceException();
    
                return observable.ObserveOn(Dispatcher.CurrentDispatcher, priority);
            }
    
            public static IObservable<T> ObserveOn<T>(this IObservable<T> observable, Dispatcher dispatcher, DispatcherPriority priority)
            {
                if (observable == null)
                    throw new NullReferenceException();
    
                if (dispatcher == null)
                    throw new ArgumentNullException("dispatcher");
    
                return Observable.CreateWithDisposable<T>(o =>
                {
                    return observable.Subscribe(
                        obj => dispatcher.Invoke((Action)(() => o.OnNext(obj)), priority),
                        ex => dispatcher.Invoke((Action)(() => o.OnError(ex)), priority),
                        () => dispatcher.Invoke((Action)(() => o.OnCompleted()), priority));
                });
            }

    • Marked as answer by Dragon89 Sunday, February 21, 2010 1:02 PM
    Sunday, February 21, 2010 1:01 PM
  • Hi, 

    Adding an ObserveOnWPFDispatcher method sounds confusing; ObserveOnDispatcher already works with WPF.  Perhaps an overload that accepts priority would be more suitable.  Although, setting the priority is not so common as I understand it, and I think the following code is readable as is anyway.

    Hi, 

    Adding an ObserveOnWPFDispatcher method sounds confusing; ObserveOnDispatcher already works with WPF.  Perhaps an overload that accepts priority would be more suitable.  Although, setting the priority is not so common as I understand it, and I think the following code is readable as is anyway.

    var views = from image in images.ToObservable()
          select CreateImageView(image);
    
    var</SPA> dispatcher = Application.Current.Dispatcher;
    var priority = DispatcherPriority.Loaded;
    
    views.Subscribe(view => dispatcher.Invoke(priority, (Action) (() => imagesViews.Add(view))));
    


    - Dave


    - Dave


    I'm still studying it, What does the example mean? Thank you!
    Friday, August 06, 2010 2:50 AM
  • Using the above implementation, I can effectively chain my async calls to be called on a low dispatcher priority:

            Observable.Defer(() => myService.QueryAsync(myquery)) 
              .ObserveOnDispatcher(DispatcherPriority.Background)
              .Repeat()                     
              .Select(ProcessResponce)              
      ...
    

    The problem is, ObserveOnDispatcher takes the thread to the UI and there is still some processing left to do (ProcessResponce). One solution would be to add .ObserveOn(Scheduler.TaskPool) right after .ObserveOnDispatcher, but I'm not sure this would be right thing to do (at least is goes against RX design guidelines).

    So, what would be the most effective way to schedule an observable on the TaskPool, but accordingly to the dispatcher priority?

    Friday, November 05, 2010 7:20 PM