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线程启动时创建的静态方法造成的?
如果你这样做——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"内置属性。