Как получить контекст синхронизации 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 который принимает либо IScheduler или SynchronizationContext, но я не знаю, как получить контекст синхронизации основного потока, и единственные планировщики, которые я мог найти, были статические свойства Scheduler, такие как Scheduler.CurrentThread, Immediate, NewThread, TaskPool а также ThreadPool, ни один из которых не работал.

Моя версия Rx 1.0.10621.

1 ответ

Решение

Сразу после публикации вопроса я нахожу решение:

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

Эта ссылка была полезной. Две заметки:

  • Не все потоки имеют контекст синхронизации, но первая форма, созданная в потоке, установит контекст синхронизации для этого потока, поэтому поток пользовательского интерфейса всегда имеет такой.
  • Правильный метод ObserveOnне SubscribeOn, На данный момент я не знаю достаточно об этом, чтобы знать почему, поэтому любые ссылки в комментариях будут оценены.

редактировать: благодаря первой части этой ссылки, теперь я понимаю больше о разнице между ObserveOn а также SubscribeOn, Короче:

  • Наблюдаемая, которая наблюдает в контексте синхронизации, вызовет методы IObserver (OnNext и друзья) из этого контекста. В моем примере я наблюдаю за потоком main/UI, поэтому я не получаю исключений между потоками
  • SubscribeOn немного сложнее, поэтому вот пример: Concat берет несколько наблюдаемых и объединяет их в одну длинную наблюдаемую. Однажды наблюдаемые звонки OnCompletedобъединенная наблюдаемая будет распоряжаться этой подпиской и подписываться на следующую наблюдаемую. Все это происходит в потоке, который называется OnCompleted, но могут быть некоторые проблемы с подпиской на наблюдаемые, которые были созданы Observable.FromEventНапример, Silverlight сгенерирует, если вы добавите обработчик событий из другого потока, отличного от потока пользовательского интерфейса, а WinForms и WPF сгенерируют, если вы добавите обработчики событий из нескольких разных потоков. SubscribeOn позволит вам контролировать поток, в котором ваши наблюдаемые подключаются к основному событию.
Другие вопросы по тегам