6

I have a WPF Code which looks something like this.

public class AlphaProductesVM : BaseModel
{
    private  ObservableCollection<Alphabetical_list_of_product> _NwCustomers;
    private int i = 0;

    public AlphaProductesVM ()
    {
        _NwCustomers = new ObservableCollection<Alphabetical_list_of_product>();
        var repository = new NorthwindRepository();
           repository
               .GetAllProducts()
               .ObserveOn(SynchronizationContext.Current)
               .Subscribe(AddElement);
    }
    public void AddElements(IEnumerable<Alphabetical_list_of_product> elements)
    {
        foreach (var alphabeticalListOfProduct in elements)
        {
            AddElement(alphabeticalListOfProduct);
        }
    }


    public ObservableCollection<Alphabetical_list_of_product> NwCustomers
    {
        get { return _NwCustomers; }
        set { _NwCustomers = value; }
    }}

I use Unity to Resolve the above AlphaProductesVM. This is instant when the Module is discovered using PRISM and the UnityBootstrapper. At runtime .ObserveOn(SynchronizationContext.Current) throws an exception and SynchronizationContext.Current has a null value in it.

Enrico Campidoglio
  • 56,676
  • 12
  • 126
  • 154
Arshad Badar Khan
  • 942
  • 1
  • 12
  • 32

3 Answers3

7

The SynchronizationContext.Current property will only return a value when invoked on the main thread.

If you need to use a SynchronizationContext object in threads other than the main thread, you could pass the SynchronizationContext instance associated to the main thread to the classes that need it as a dependency.

If you choose this solution, you could register the SynchronizationContext object obtained from the SynchronizationContext.Current property on the main thread as a singleton in your container. That way all requests for a SynchronizationContext from that point on will automatically be satisfied by the container with the singleton:

// Must run in the main thread
container.RegisterInstance(SynchronizationContext.Current);
Enrico Campidoglio
  • 56,676
  • 12
  • 126
  • 154
  • The `SetSynchronizationContext` function call only sets the `SynchronizationContext` for the running thread. Meaning that the second option that you mention, "assign in the main thread", does not have an effect on the other threads. (Wrote a gist to prove that: https://gist.github.com/3225564 ) – Jean Hominal Aug 01 '12 at 09:59
  • @JeanHominal You're absolutely correct, thanks for pointing that out. I updated my answer. – Enrico Campidoglio Aug 01 '12 at 14:15
  • 1
    Readers should be aware that in .NET 4.0, SynchronizationContext.Current can be null on the main thread. See http://stackoverflow.com/questions/11621372/. Enrico's suggestion is good to store it away as a singleton in your container early in your application. – Wallace Kelly Jan 23 '14 at 20:34
0

Although there is an implementation of SynchronizationContextfor WPF it is not recommended for use. WPF has the Dispatcher to build responsive applications.

In addition SynchronizationContext.Current only has a value if you are on the UI thread. If your logic runs in a background thread Current will always be null.

Sebastian Weber
  • 6,766
  • 2
  • 30
  • 49
  • 1
    *" it is not recommended for use"* Do you have a reference for that? In a WPF application, **SynchronizationContext.Current** returns an instance of type [DispatcherSynchronizationContext](http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatchersynchronizationcontext.aspx) which is a SC that uses the Dispatcher. –  Feb 21 '12 at 16:28
  • I can only find the [reference for Silverlight](http://wildermuth.com/2009/04/12/For_Now_Don_t_Use_SynchronizationContext_in_Silverlight_2_or_3) but I experienced the same behavior in WPF. – Sebastian Weber Feb 21 '12 at 17:49
0

I'm not sure if this will be a popular suggestion, but you could lazily create and subscribe to your collection. Then the first access to NwCustomers from the UI thread will kick everything off correctly.

public AlphaProductesVM (){}

public ObservableCollection<Alphabetical_list_of_product> NwCustomers
{
    get { 
          if(_NwCustomers == null)
          {
              _NwCustomers = new ObservableCollection<Alphabetical_list_of_product>();
              var repository = new NorthwindRepository();
                  repository
                  .GetAllProducts()
                  .ObserveOn(SynchronizationContext.Current)
                  .Subscribe(AddElement);
          }
          return _NwCustomers; 
    }
}

or, if you inject the UI thread's dispatcher into your view model you can subscribe on that in the constructor.

              var repository = new NorthwindRepository();
                  repository
                  .GetAllProducts()
                  .ObserveOn(theUIdispatcher)
                  .Subscribe(AddElement);
Phil
  • 42,255
  • 9
  • 100
  • 100