为什么这个 Observable 会阻塞 WPF GUI 线程 (C#)?
Why is this Observable blocking the WPF GUI thread (C#)?
给定:采用 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 用于提取元素的 Webdriver?
或者这是因为在 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,但我是这样看的...我想要 observable订阅一些调度程序。 (我认为更好的名字应该是 "SheduleOn")。
ObserveOn 方法名称很有意义。但是请注意 "Scheduler.Dispatcher" built-in 属性。
给定:采用 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 用于提取元素的 Webdriver?
或者这是因为在 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,但我是这样看的...我想要 observable订阅一些调度程序。 (我认为更好的名字应该是 "SheduleOn")。
ObserveOn 方法名称很有意义。但是请注意 "Scheduler.Dispatcher" built-in 属性。