2011-09-14 55 views
12

我有一個WinForm應用程序一個WinForm同步上下文或時間表,以及可觀察到的設立是這樣的:如何獲得一個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); 

這不起作用,因爲l => lb.Text = l.ToString()就不會運行在創建窗體的主線程上,但我無法弄清楚如何讓它在這個線程上運行。我假設,我應該使用IObservable.SubscribeOn,它可以採用ISchedulerSynchronizationContext,但我不知道如何獲取主線程的同步上下文,並且唯一可以找到的調度程序是Scheduler的靜態屬性,例如Scheduler.CurrentThreadImmediate,NewThread,TaskPoolThreadPool,其中沒有一個工作。

我的Rx版本是1.0.10621。

回答

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); 

This鏈接是有益的。有兩點需要注意:

  • 並非所有的線程有同步環境,但大幹快上一個線程創建將設置線程同步上下文中的第一種形式,所以在UI線程總是有一個。
  • 正確的方法是ObserveOn而不是SubscribeOn。目前,我對此知之甚少,不知道爲什麼,所以在評論中的任何鏈接都將不勝感激。

編輯:感謝this鏈接的第一部分,我現在更多地瞭解ObserveOnSubscribeOn之間的差異。總之:

  • 觀察同步上下文的observable將從該上下文調用IObserver方法(OnNext和朋友)。在我的例子中,我觀察到了主/ UI線程,所以我沒有交叉線程異常
  • SubscribeOn有點複雜,所以這裏有一個例子:Concat需要一些觀察值並將它們組合到一個長觀察值。一旦可觀察到的電話OnCompleted,合併的可觀察到的將處置該訂閱,並訂閱下一個觀察。這一切都發生在調用OnCompleted的線程上,但訂閱觀察者時可能會遇到一些問題,這些問題是由Observable.FromEvent創建的,例如,如果您從UI線程以外的其他線程添加事件處理程序,則Silverlight將拋出,如果您添加來自多個不同線程的事件處理程序,則WinForms和WPF將拋出。 SubscribeOn將允許您控制您的observable掛鉤到底層事件的線程。
+7

'SubscribeOn'只設置發生實際訂閱的線程,而'ObserveOn'確定執行'OnNext'調用的線程。爲了與事件進行比較,'SubscribeOn'就像讓你只在主線程中添加事件處理程序,但是'ObserveOn'確保事件處理例程在正確的線程中被調用。 –

+0

@Gideon:謝謝。我編輯了我的答案,以反映我對改進的理解,但您的意見總結得很好。 – Boris

+2

如果您有System.Reactive.Windows.Forms.dll的引用,您可以執行.ObserveOn(表單),它將執行與Control.Invoke等效的操作。 –