Ответ 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
. На данный момент я не знаю достаточно об этом, чтобы знать, почему, поэтому любые ссылки в комментариях будут оценены.
edit: Благодаря первой части этой ссылки я теперь больше понимаю разницу между ObserveOn
и SubscribeOn
. Короче говоря:
- Наблюдаемый, наблюдаемый в контексте синхронизации, вызовет методы IObserver (
OnNext
и друзей) из этого контекста. В моем примере я наблюдаю за потоком основного/пользовательского интерфейса, поэтому поэтому я не вижу исключений для перекрестных потоков -
SubscribeOn
немного сложнее, поэтому вот пример: Concat берет ряд наблюдаемых и объединяет их в один длинный наблюдаемый. Как только наблюдаемые вызовыOnCompleted
, объединенные наблюдаемые будут распоряжаться этой подпиской и подписаться на следующее наблюдаемое. Все это происходит в потоке, который называетсяOnCompleted
, но могут возникнуть проблемы с подпиской на наблюдаемые, которые были созданыObservable.FromEvent
, например. Silverlight будет бросать, если вы добавите обработчик событий из другого потока, кроме потока пользовательского интерфейса, а WinForms и WPF будут метаться, если вы добавите обработчики событий из нескольких разных потоков.SubscribeOn
позволит вам контролировать поток, на котором ваши наблюдаемые привязки попадают в основное событие.