2017-10-04 13 views
4

私はRxUI 8の最新のプレリリース版を使用していますが、これは以前のバージョンで起こると思います。私は私のWPFアプリケーションでこのReactiveCommandを定義したReactiveUIコマンド並行処理(WebClient)

GetWebsiteCommand = ReactiveCommand.CreateFromTask(DownloadString); 

private async Task<string> DownloadString() 
{ 
    using (var client = new WebClient()) 
    { 
     return await client.DownloadStringTaskAsync("http://www.google.es"); 
    } 
} 

コマンドを実行すると、次の例外がスローされます。

のSystem.InvalidOperationException」System.Reactive.Coreで。 dll:別のスレッド が所有しているため、 呼び出しスレッドはこのオブジェクトにアクセスできません

なぜこれが起こっていますか?私は新しいスレッドを作成していません!

これはスタックトレースです:System.Reactive.Core.dllで

のSystem.InvalidOperationException」:別のスレッド が

at System.Windows.Threading.Dispatcher.VerifyAccess() 
    at System.Windows.DependencyObject.GetValue(DependencyProperty dp) 
    at System.Windows.Controls.Primitives.ButtonBase.get_Command() 
    at System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute() 
    at System.Windows.Controls.Primitives.ButtonBase.OnCanExecuteChanged(Object sender, EventArgs e) 
    at System.Windows.Input.CanExecuteChangedEventManager.HandlerSink.OnCanExecuteChanged(Object sender, EventArgs e) 
    at ReactiveUI.ReactiveCommand.OnCanExecuteChanged() 
    at ReactiveUI.ReactiveCommand`2.<.ctor>b__9_5(Boolean _) 
    at System.Reactive.AnonymousSafeObserver`1.OnNext(T value) 
    at System.Reactive.Linq.ObservableImpl.RefCount`1._.OnNext(TSource value) 
    at System.Reactive.Subjects.FastImmediateObserver`1.EnsureActive(Int32 count) 
    at System.Reactive.Subjects.FastImmediateObserver`1.EnsureActive() 
    at System.Reactive.Subjects.ReplaySubject`1.ReplayBase.OnNext(T value) 
    at System.Reactive.Subjects.ReplaySubject`1.OnNext(T value) 
    at System.Reactive.Linq.ObservableImpl.AsObservable`1._.OnNext(TSource value) 
    at System.Reactive.Linq.ObservableImpl.DistinctUntilChanged`2._.OnNext(TSource value) 
    at System.Reactive.Linq.ObservableImpl.CombineLatest`3._.S.OnNext(TSecond value) 
    at System.Reactive.Linq.ObservableImpl.RefCount`1._.OnNext(TSource value) 
    at System.Reactive.Subjects.FastImmediateObserver`1.EnsureActive(Int32 count) 
    at System.Reactive.Subjects.FastImmediateObserver`1.EnsureActive() 
    at System.Reactive.Subjects.ReplaySubject`1.ReplayBase.OnNext(T value) 
    at System.Reactive.Subjects.ReplaySubject`1.OnNext(T value) 
    at System.Reactive.Linq.ObservableImpl.AsObservable`1._.OnNext(TSource value) 
    at System.Reactive.Linq.ObservableImpl.DistinctUntilChanged`2._.OnNext(TSource value) 
    at System.Reactive.Linq.ObservableImpl.Concat`1._.OnNext(TSource value) 
    at System.Reactive.Linq.ObservableImpl.Select`2._.OnNext(TSource value) 
    at System.Reactive.SafeObserver`1.OnNext(TSource value) 
    at System.Reactive.ScheduledObserver`1.Dispatch(ICancelable cancel) 
    at System.Reactive.Concurrency.Scheduler.<>c.<ScheduleLongRunning>b__72_0(Action`1 a, ICancelable c) 
    at System.Reactive.Concurrency.DefaultScheduler.LongRunning.<>c__DisplayClass1_0`1.<ScheduleLongRunning>b__0(Object arg) 
    at System.Reactive.Concurrency.ConcurrencyAbstractionLayerImpl.<>c__DisplayClass7_0.<StartThread>b__0() 
    at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
    at System.Threading.ThreadHelper.ThreadStart() 
それを所有しているため、スレッドを呼び出す は、このオブジェクトにアクセスすることはできません
+0

新しいスレッドは作成されていませんか?多分あなたはタスクの概念に精通していないかもしれません。情報[ –

+0

@CamiloTerevintoについては[この記事を読む](https://docs.microsoft.com/en-us/dotnet/csharp/async)を参照してください。いいえ、私は新しいスレッドを作成していません。スレッドはどこに作成されますか?私が知っていることについては、タスクはスレッドの作成を伴いません。 WebClient.DownloadStringTaskAsyncメソッドが別のスレッドでタスクを実行しているかどうかを知っていますか? – SuperJMN

+0

@CamiloTerevinto Task.FromResult(()=> 1)が新しいスレッドで実行されるかどうか教えてください。理由なくdownvotingをやめてください。有用な答えを出してください。それ以外の場合は、他の人にしましょう。 – SuperJMN

答えて

2

スタックトレースで判断すると、canExecuteパイプラインがコマンドに渡されます。あなたが提供するパイプラインについては、正しいスレッド上で確実に確認する責任があります。バックグラウンドスレッドで目立つ場合、コマンドCanExecuteが同じスレッドでチェックされるため、UIは関連するButtonIsEnabledプロパティを間違ったスレッドから更新しようとします。

したがって、canExecuteパイプラインに対してObserveOnコールを追加する必要があります。

更新:hereと回答しました。

+0

ありがとう、ケント!しかし、私はCanExecuteパイプラインを通過していません。コマンドは 'ReactiveCommand.CreateFromTask(DownloadString);'という行で作成されますので、タスクを渡すだけです。コードを実行できますか?これらの単純な線で、問題を再現することができます。 – SuperJMN