为什么这个Observable阻塞了WPF GUI线程(C#)

本文关键字:线程 GUI WPF Observable 为什么 | 更新日期: 2023-09-27 18:29:20

Given:一个扩展方法,采用Selenium IWebdriver实例并返回一个IObservable

     public static IObservable<ObservableCollection<WebElementWrapper>> 
      GetAllElementsAsObservable(this IWebDriver wd)
      {
        return Observable.Create<ObservableCollection<WebElementWrapper>>(
             (IObserver<ObservableCollection<WebElementWrapper>> observer) =>
             {                     
                     var eles = wd.FindElements(By.CssSelector("*"));
                     var list = eles.ToWebElementObservableCollection();
                     observer.OnNext(list);
                     observer.OnCompleted();                     
                 return Disposable.Create(() => { });
             });
      }

调用上面方法的代码(在GUI线程上运行)。。。

                //GUI Will Freeze on this call until OnCompleted is called
                cd.GetAllElementsAsObservable().Subscribe((WEWList) =>
                {
                    WebElementCollection = WEWList;
                    SetNavigationItems();
                });

在调用OnCompleted之前,有人能帮我确定GUI线程阻塞的根本原因吗。如果我在第一个方法中使用Task.Run,我可以停止阻塞,但之后我必须将集合整理回GUI线程。

这是因为GUI线程启动了Observable用来提取元素的Web驱动程序而阻止的吗?

或者这是由于在GUI线程启动时创建的静态方法造成的?

为什么这个Observable阻塞了WPF GUI线程(C#)

如果你这样做——Disposable.Create(() => { })——你做错了什么。使用Observable.Create的方式是阻塞操作。.Create中的代码是订阅的一部分,但您在订阅期间运行观察器直到完成,这就是它被阻止的原因。

试着这样做:

public static IObservable<ObservableCollection<WebElementWrapper>>
    GetAllElementsAsObservable(this IWebDriver wd)
{
    return Observable.Create<ObservableCollection<WebElementWrapper>>(observer =>
        Observable
            .Start(() =>
                wd
                    .FindElements(By.CssSelector("*"))
                    .ToWebElementObservableCollection())
            .Subscribe(observer));
}

对于WPF,我还发现了这两种方法。。

SomeObservable
.SubscribeOn(Scheduler.Default)
.ObserveOn(Scheduler.CurrentThread)
.Subscribe(item => { //do something on gui thread here });

我不喜欢方法名称SubscribeOn,但我是这样看的。。。我希望可观察在某个调度程序上订阅。(我想一个更好的名字应该是"SheduleOn")。

ObserveOn方法名称是有意义的。但请注意"Scheduler.Dispatcher"内置属性。