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はスレッドプールを使用しているため、UIスレッドではOnNextは発生しません。ただし、SubscribeOnDispatcherはそれをUIスレッドにマーシャリングする必要があります。いけませんか?

4

2 に答える 2

13

SubscribeOnDispatcherについてのあなたの理解は正しくありません。まず、2つの*On演算子を区別しましょう。

  • SubscribeOn *-指定されたスケジューラーで(非)サブスクリプションロジックを実行します。Observable.Createなどで遊んでいない限り、めったに使用されません。
  • ObserveOn *-指定されたスケジューラーでオブザーバーメッセージ(OnNext、OnError、OnCompleted)を実行します。サブスクライブに渡された「イベントハンドラー」を実行するときのUI同期に主に使用されます。

サンプルを機能させるには、クエリのさらに下流でObserveOn演算子の使用を固定する必要もあります。最後のサブスクライブ呼び出しの直前にこれを行うことをお勧めします。クエリ内で、Throttle(デフォルトのスケジューラーはスレッドプール)などのオペレーターによって並行性を導入できます。同期の保証が必要な場合にのみ、*On演算子を導入してください。

スロットル呼び出しをパラメータ化するというPaulの提案も良いものです。導入されたすべての並行性を制御できる場合は、そうすることをお勧めします。ただし、同期要件に関して動作が悪く、* On演算子を使用する必要がある、IObservableシーケンスが渡される場合が多くあります。

于 2012-01-09T20:47:44.720 に答える
6

行を次のように変更するだけです。

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

とにかくそれはより効率的です(33msは本当に短いタイムスパンスロットルであり、タイマーの解像度にぶつかりますが)

于 2012-01-07T03:12:38.393 に答える