Как получить контекст синхронизации 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
позволит вам контролировать поток, в котором ваши наблюдаемые подключаются к основному событию.