2012-01-07 5 views
5

Я получаюисключение Cross нить при использовании RX Дроссель

Invalid доступ кросс-нить.

При использовании RX Дроссель

Вот мой код:

 yObs.SubscribeOnDispatcher() 
      .DistinctUntilChanged() 
      .Throttle(TimeSpan.FromMilliseconds(33)) 
      .SkipWhile(y => !_isDragging) 
      .Subscribe(y => 
          { 
           // Exception when trying to access image 
           image.RenderTransform = new CompositeTransform() { TranslateY = -y }; 
           _vm.UpdateContentDrag(y/image.ActualHeight * 100); 
          }); 

Но если я опускаю дроссельная все работает.

Насколько я понимаю, Throttle использует пул потоков, поэтому OnNext не происходит в потоке пользовательского интерфейса. Но SubscribeOnDispatcher должен перевести его обратно в поток пользовательского интерфейса. Не так ли?

ответ

12

Ваше понимание SubscribeOnDispatcher неверен. Прежде всего, давайте различать два оператора: On:

  • ПодписатьсяOn * - Запускает (un) подписку на указанный планировщик. Редко используется, если вы не играете с Observable.Create и т. Д.
  • ObserveOn * - Запускает сообщения наблюдателя (OnNext, OnError, OnCompleted) в указанном планировщике. В основном используется для синхронизации пользовательского интерфейса при запуске «обработчиков событий», переданных в «Подписаться».

Для того, чтобы ваш образец работал, вы также должны придерживаться оператора ObserveOn в дальнейшем по запросу. Наша рекомендация - сделать это прямо перед заключительным призывом к подписке. Внутри запроса параллелизм может быть введен операторами, такими как Throttle (чей планировщик по умолчанию - это пул потоков). Только в тот момент, когда вам нужны гарантии синхронизации, введите оператор * On.

Предложение Павла параметризовать вызов Throttle также является хорошим. В случаях, когда вы можете контролировать все введенные параллелизма, вы можете это сделать. Тем не менее, есть много случаев, когда вам передается последовательность IObservable, которая плохо себя ведет в отношении требований к синхронизации, требуя использования операторов * On.

4

Просто измените линию:

.Throttle(TimeSpan.FromMilliseconds(33), DispatcherScheduler.Instance) 

Это более эффективно в любом случае (хотя 33ms действительно короткий промежуток времени дроссельной заслонки, ударяя против разрешения таймера)

+0

Спасибо, это работает. – Vitalij