ReactiveUI 命令并发(WebClient)

ReactiveUI Command concurrency (WebClient)

我使用的是最新的 RxUI 8 预发布版,但我认为这会发生在以前的版本中。

我已经在我的 WPF 应用程序中定义了这个 ReactiveCommand:

GetWebsiteCommand = ReactiveCommand.CreateFromTask(DownloadString);

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

执行命令时,抛出如下异常:

System.InvalidOperationException' at System.Reactive.Core.dll: The calling thread cannot access this object because a different thread owns it

为什么会这样?我不会创建任何新线程!

这是堆栈跟踪:

System.InvalidOperationException' at System.Reactive.Core.dll: The calling thread cannot access this object because a different thread owns it

 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()

根据堆栈跟踪判断,您正在将 canExecute 管道传递到命令中。对于您提供的任何管道,您有责任确保它在正确的线程上运行。如果它在后台线程上运行,命令 CanExecute 事件将在同一线程上运行,因此 UI 将尝试在关联的 [=] 上更新 IsEnabled 属性 13=] 来自错误的线程。

因此,您可能需要针对 canExecute 管道添加 ObserveOn 调用。

更新:已回答 here