5

我正进入(状态

无效的跨线程访问。

使用 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 不会发生在 UI 线程上。但是 SubscribeOnDispatcher 应该将其编组回 UI 线程。不应该吗?

4

2 回答 2

13

您对 SubscribeOnDispatcher 的理解是不正确的。首先,让我们区分两个 *On 运算符:

  • SubscribeOn* - 在指定的调度程序上运行(取消)订阅逻辑。很少使用,除非您使用 Observable.Create 等。
  • ObserveOn* - 在指定的调度程序上运行观察者消息(OnNext、OnError、OnCompleted)。在运行传递给订阅的“事件处理程序”时,主要用于 UI 同步。

为了让您的示例正常工作,您还应该在查询的下游继续使用 ObserveOn 运算符。我们的建议是在最后的订阅电话之前这样做。在查询中,可以通过诸如 Throttle(其默认调度程序是线程池)之类的运算符来引入并发性。只有在您需要同步保证时,才引入 *On 运算符。

Paul 参数化 Throttle 调用的建议也是一个很好的建议。在您可以控制所有引入的并发的情况下,您可能希望这样做。但是,在许多情况下,您会收到一个 IObservable 序列,该序列在同步要求方面表现不佳,需要使用 *On 运算符。

于 2012-01-09T20:47:44.720 回答
6

只需将行更改为:

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

无论如何它更有效(尽管 33ms 是一个非常短的时间跨度油门,与计时器分辨率相冲突)

于 2012-01-07T03:12:38.393 回答