如何在WinForm线程上获取WinForm同步上下文或计划

Bor*_*ris 12 .net-4.0 winforms synchronizationcontext system.reactive

我有一个winform应用程序,一个可观察的设置如下:

Form form = new Form();
Label lb = new Label();
form.Controls.Add(lb);

Observable.Interval(TimeSpan.FromSeconds(1))
          .Subscribe(l => lb.Text = l.ToString());

Application.Run(form);
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为l => lb.Text = l.ToString()不会在创建表单的主线程上运行,但我无法弄清楚如何使它在此线程上运行.我想,我应该用IObservable.SubscribeOn这需要一个或者ISchedulerSynchronizationContext,但我不知道如何让主线程的的SynchronizationContext,唯一的调度程序,我能找到人的静态属性Scheduler,如Scheduler.CurrentThread,Immediate,NewThread,TaskPoolThreadPool,没有一个有效.

我的Rx版本是1.0.10621.

Bor*_*ris 23

在我发布问题之后,我找到了解决方案:

Form form = new Form();
Label lb = new Label();
form.Controls.Add(lb);

Observable.Interval(TimeSpan.FromSeconds(2))
          .ObserveOn(SynchronizationContext.Current)
          .Subscribe(l => lb.Text = l.ToString());

Application.Run(form);
Run Code Online (Sandbox Code Playgroud)

这个链接很有帮助.两个笔记:

  • 并非所有线程都具有同步上下文,但是在线程上创建的第一个表单将为该线程设置同步上下文,因此UI线程始终具有一个.
  • ObserveOn没有正确的方法SubscribeOn.目前,我对此知之甚少,所以评论中的任何链接都会受到赞赏.

编辑:由于第一部分链接,我现在更多的了解之间的差异ObserveOnSubscribeOn.简而言之:

  • 观察同步上下文的observable将从该上下文调用IObserver方法(OnNext和朋友).在我的例子中,我在main/UI线程上观察,因此我没有得到跨线程异常
  • SubscribeOn稍微复杂一点,所以这里有一个例子:Concat采用了许多可观察对象并将它们组合成一个长的可观察对象.一旦发出可观察的调用OnCompleted,组合的observable将处理该订阅,并订阅下一个observable.这一切都发生在调用的线程上OnCompleted,但是订阅observable可能存在一些问题Observable.FromEvent,例如,如果你从另一个线程中添加一个事件处理程序而不是UI线程,则会抛出Silverlight,而WinForms和WPF将抛出您从多个不同的线程添加事件处理程序.SubscribeOn将允许您控制您的observable连接到基础事件的线程.

  • `SubscribeOn`只设置实际订阅发生的线程,而`ObserveOn`确定`OnNext`调用哪个线程执行.为了与事件进行比较,`SubscribeOn`就像让你只在主线程上添加事件处理程序,但是`ObserveOn`确保在正确的线程上调用事件处理例程. (8认同)
  • 如果您有对System.Reactive.Windows.Forms.dll的引用,则可以执行.ObserveOn(form),它将执行与Control.Invoke相同的操作. (3认同)