【问题标题】:SynchronizationContext.Current is null on resolving with Unity in WPF在 WPF 中使用 Unity 解析时 SynchronizationContext.Current 为空
【发布时间】:2012-02-21 12:03:48
【问题描述】:

我有一个看起来像这样的 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 值。

【问题讨论】:

    标签: c# wpf mvvm unity-container system.reactive


    【解决方案1】:

    SynchronizationContext.Current 属性只会在主线程调用时返回一个值

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

    如果您选择此解决方案,您可以将从主线程上的SynchronizationContext.Current 属性获得的SynchronizationContext 对象注册为容器中的单例。这样,从那时起,所有对 SynchronizationContext 的请求都将自动由具有单例的容器满足:

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

    【讨论】:

    • SetSynchronizationContext 函数调用只为正在运行的线程设置SynchronizationContext。这意味着您提到的第二个选项“在主线程中分配”对其他线程没有影响。 (写了一个要点来证明:gist.github.com/3225564
    • @JeanHominal 您说的完全正确,感谢您指出这一点。我更新了我的答案。
    • 读者应该知道,在 .NET 4.0 中,SynchronizationContext.Current 在主线程上可以为 null。见stackoverflow.com/questions/11621372。 Enrico 的建议是在应用程序的早期将其作为单例存储在容器中。
    【解决方案2】:

    虽然有一个SynchronizationContextfor WPF 的实现,但不推荐使用它。 WPF 有Dispatcherbuild responsive applications

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

    【讨论】:

    • " 不推荐使用" 你有参考吗?在 WPF 应用程序中,SynchronizationContext.Current 返回一个 DispatcherSynchronizationContext 类型的实例,它是一个使用 Dispatcher 的 SC。
    • 我只能找到reference for Silverlight,但我在 WPF 中遇到了同样的行为。
    【解决方案3】:

    我不确定这是否会是一个受欢迎的建议,但您可以懒惰地创建并订阅您的收藏。然后从 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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-27
      • 1970-01-01
      • 1970-01-01
      • 2013-01-21
      • 2016-12-29
      • 1970-01-01
      相关资源
      最近更新 更多