简体   繁体   English

ReactiveUI命令并发(WebClient)

[英]ReactiveUI Command concurrency (WebClient)

I'm using the latest prerelease of RxUI 8, but I think this would happen in prior versions. 我正在使用RxUI 8的最新预发行版,但我认为这将在以前的版本中发生。

I have defined this ReactiveCommand in my WPF application: 我在我的WPF应用程序中定义了这个ReactiveCommand:

GetWebsiteCommand = ReactiveCommand.CreateFromTask(DownloadString);

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

When the command is executed, the following exception is thrown: 执行该命令时,将引发以下异常:

System.InvalidOperationException' at System.Reactive.Core.dll: The calling thread cannot access this object because a different thread owns it System.Reactive.Core.dll中的System.InvalidOperationException:调用线程无法访问此对象,因为另一个线程拥有它

Why is this happening? 为什么会这样? I'm not creating any new thread! 我没有创建任何新线程!

This is the Stack Trace: 这是堆栈跟踪:

System.InvalidOperationException' at System.Reactive.Core.dll: The calling thread cannot access this object because a different thread owns it 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()

Judging by the stack trace, you are passing a canExecute pipeline into the command. 通过堆栈跟踪判断,您将canExecute管道传递给命令。 For any pipeline you provide, you are responsible for ensuring it ticks on the correct thread. 对于您提供的任何管道,您有责任确保它在正确的线程上打勾。 If it ticks on a background thread, the commands CanExecute event will tick on that same thread and the UI will therefore attempt to update the IsEnabled property on the associated Button from the wrong thread. 如果它在后台线程上打勾,则命令CanExecute事件将在同一个线程上打勾,因此UI将尝试从错误的线程更新关联Button上的IsEnabled属性。

So you likely need to add an ObserveOn call against your canExecute pipeline. 因此,您可能需要针对canExecute管道添加ObserveOn调用。

UPDATE: answered here . 更新: 在这里回答。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM