使用Unity在WPF中解析时,SynchronizationContext.Current为null

6
我有一段类似于这样的WPF代码。
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; }
    }}

我使用Unity解决上述问题的AlphaProductesVM。当使用PRISM和UnityBootstrapper发现模块时,即时执行。在运行时,.ObserveOn(SynchronizationContext.Current)会触发异常,而SynchronizationContext.Current则具有空值null

3个回答

7

SynchronizationContext.Current属性只有在主线程中调用时才会返回值。

如果你需要在除主线程外的线程中使用SynchronizationContext对象,可以将与主线程相关联的SynchronizationContext实例作为依赖项传递给需要它的类。

如果选择此解决方案,则可以将从SynchronizationContext.Current属性获得的SynchronizationContext对象在容器中注册为一个单例。这样,从此以后对SynchronizationContext的所有请求都将自动由容器满足单例的需求:

// Must run in the main thread
container.RegisterInstance(SynchronizationContext.Current);

SetSynchronizationContext 函数调用仅为运行线程设置 SynchronizationContext。这意味着您提到的第二个选项“在主线程中分配”不会影响其他线程。(编写了一个 gist 以证明:https://gist.github.com/3225564) - Jean Hominal
@JeanHominal 您说得完全正确,感谢您指出。我已经更新了我的答案。 - Enrico Campidoglio
1
读者应该注意,在.NET 4.0中,主线程上的SynchronizationContext.Current可能为null。请参见https://dev59.com/smgu5IYBdhLWcg3wDS0G。Enrico的建议是,在应用程序早期将其作为单例存储在你的容器中。 - Wallace Kelly

0
我不确定这是否是一个受欢迎的建议,但你可以懒惰地创建和订阅你的集合。然后,来自 UI 线程对 NwCustomers 的第一次访问将正确地启动所有内容。
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; 
    }
}

或者,如果你将UI线程的调度程序注入到你的视图模型中,你可以在构造函数中订阅它。

              var repository = new NorthwindRepository();
                  repository
                  .GetAllProducts()
                  .ObserveOn(theUIdispatcher)
                  .Subscribe(AddElement);

0

虽然WPF有SynchronizationContext的实现,但不建议使用。WPF有Dispatcher构建响应式应用程序

此外,只有在UI线程上时SynchronizationContext.Current才有值。如果您的逻辑在后台线程运行,则Current将始终为null。


1
“不建议使用” 这个词用得非常普遍。你有相关的参考资料吗?在 WPF 应用程序中, SynchronizationContext.Current 返回一个 DispatcherSynchronizationContext 类型的实例,这是一个使用 Dispatcher 的 SC。 - user1228
我只能找到关于Silverlight的参考资料(http://wildermuth.com/2009/04/12/For_Now_Don_t_Use_SynchronizationContext_in_Silverlight_2_or_3),但我在WPF中也遇到了相同的现象。 - Sebastian Weber

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接