4

I'm using the latest prerelease of RxUI 8, but I think this would happen in prior versions.

I have defined this ReactiveCommand in my WPF application:

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

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

 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()
SuperJMN
  • 13,110
  • 16
  • 86
  • 185
  • You are not creating any new thread? Maybe you are not familiar with the concept of Task. Read [this article](https://learn.microsoft.com/en-us/dotnet/csharp/async) for information – Camilo Terevinto Oct 04 '17 at 22:15
  • @CamiloTerevinto. No, I'm not creating any new Thread. Where am I creating a Thread? For what I know, a Task DOES NOT involve the creation of any Thread. Do you know if WebClient.DownloadStringTaskAsync method is running the task on a different thread? – SuperJMN Oct 04 '17 at 22:35
  • @CamiloTerevinto Can you, please, tell me whether Task.FromResult( () => 1) runs on a new Thread? Stop downvoting without a reason, please, and start giving useful answers. Otherwise, let other people do. – SuperJMN Oct 04 '17 at 22:40
  • 4
    @SuperJMN do you have a stack trace for the exception? I suspect something else is triggering this as a result of the command execution. The reactive command will guarantee output is delivered via `RxApp.MainThreadScheduler`, so I'm guessing there's something else going on here... – me-- Oct 04 '17 at 23:34
  • @me-- Please, check the OP. I've added the stack trace. – SuperJMN Oct 05 '17 at 10:13

1 Answers1

2

Judging by the stack trace, you are passing a canExecute pipeline into the command. 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.

So you likely need to add an ObserveOn call against your canExecute pipeline.

UPDATE: answered here.

Kent Boogaart
  • 175,602
  • 35
  • 392
  • 393
  • 1
    Thank you, Kent! But I'm not passing any CanExecute pipeline. The Command is created with the line `ReactiveCommand.CreateFromTask(DownloadString);` So I'm only passing the Task. Can you, please, run the code? With those simple lines you will be able to reproduce the problem. – SuperJMN Oct 05 '17 at 11:08