1

I'm trying to write a very simple sample using Caliburn.Micro.ReactiveUI this sample combines the Basic Configuration, Actions and Conventions sample from the Caliburn.Micro Documentation with the ReactiveUI.Sample.Commands sample. The problem I have is that when any command gets called, so for both the DisplayCommand and the StartAsyncCommand, an InvalidOperationException is thrown, stating that the calling thread cannot access this object because a different thread owns it. Below I've included the code of both the View and the ViewModel, the entire sample is on GitHub the code now contains the fix suggested by Paul below.

Searching the internet did not yield any information. I guess I'm missing something obvious, any help is very much appreciated.

The viewmodel:

public class ShellViewModel : ReactivePropertyChangedBase, IShell
{
    private string personName;

    public ShellViewModel(IMessageBoxService messageBoxService)
    {
        DisplayCommand = new ReactiveCommand(this.WhenAny(x => x.PersonName, x => !string.IsNullOrEmpty(x.Value)));
        DisplayCommand.Subscribe(_ => messageBoxService.ShowMessageBox("You clicked on DisplayCommand: Name is " + PersonName));

        var localProgress = new Subject<int>();
        localProgress.ToProperty(this, x => x.Progress, out progress);

        StartAsyncCommand = new ReactiveCommand();
        StartAsyncCommand.RegisterAsyncAction(_ =>
        {
            var currentProgress = 0;
            localProgress.OnNext(currentProgress);
            while (currentProgress <= 100)
            {
                localProgress.OnNext(currentProgress += 10);
                Thread.Sleep(100);
            }
        });
    }

    public IReactiveCommand DisplayCommand { get; protected set; }

    public string PersonName
    {
        get { return personName; }
        set
        {
            this.RaiseAndSetIfChanged(ref personName, value);
        }
    }

    private ObservableAsPropertyHelper<int> progress;
    public int Progress
    {
        get { return progress.Value; }
    }

    public IReactiveCommand StartAsyncCommand { get; protected set; }
}

The view:

<Window x:Class="CaliburnMicroReactiveUI.Sample.Commands.Views.ShellView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel>
        <Expander
                IsExpanded="True"
                Header="Simple Command">
            <StackPanel>
                <TextBox
                        Text="{Binding PersonName, UpdateSourceTrigger=PropertyChanged}" />
                <Button
                        Command="{Binding DisplayCommand}"
                        Content="Display" />
            </StackPanel>
        </Expander>
        <Expander
                IsExpanded="True"
                Header="Async Command">
            <StackPanel>
                <Button Command="{Binding StartAsyncCommand}" Content="Start" />
                <ProgressBar Value="{Binding Progress, Mode=OneWay}" Height="20"/>
            </StackPanel>
        </Expander>
    </StackPanel>
</Window>

The Display button generates the following stacktrace:

System.Windows.Threading.Dispatcher.VerifyAccess()
System.Windows.DependencyObject.GetValue(DependencyProperty dp)
System.Windows.Controls.Primitives.ButtonBase.get_Command()
System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute()
System.Windows.Controls.Primitives.ButtonBase.OnCanExecuteChanged(Object sender, EventArgs e)
System.Windows.Input.CanExecuteChangedEventManager.HandlerSink.OnCanExecuteChanged(Object sender, EventArgs e)
ReactiveUI.ReactiveCommand.raiseCanExecuteChanged(EventArgs e)
ReactiveUI.ReactiveCommand.<.ctor>b__5()
System.Reactive.Concurrency.Scheduler.Invoke(IScheduler scheduler, Action action)
System.Reactive.Concurrency.DefaultScheduler.<>c__DisplayClass1`1.<Schedule>b__0(Object _)
System.Reactive.Concurrency.ConcurrencyAbstractionLayerImpl.<>c__DisplayClass1.<QueueUserWorkItem>b__0(Object _)
System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
System.Threading.ThreadPoolWorkQueue.Dispatch()
System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

The Start button creates this stacktrace:

System.Windows.Threading.Dispatcher.VerifyAccess()
System.Windows.DependencyObject.GetValue(DependencyProperty dp)
System.Windows.Controls.Primitives.ButtonBase.get_Command()
System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute()
System.Windows.Controls.Primitives.ButtonBase.OnCanExecuteChanged(Object sender, EventArgs e)
System.Windows.Input.CanExecuteChangedEventManager.HandlerSink.OnCanExecuteChanged(Object sender, EventArgs e)
ReactiveUI.ReactiveCommand.raiseCanExecuteChanged(EventArgs e)
ReactiveUI.ReactiveCommand.<.ctor>b__5()
System.Reactive.Concurrency.Scheduler.Invoke(IScheduler scheduler, Action action)
System.Reactive.Concurrency.DefaultScheduler.<>c__DisplayClass1`1.<Schedule>b__0(Object _)
System.Reactive.Concurrency.ConcurrencyAbstractionLayerImpl.<>c__DisplayClass1.<QueueUserWorkItem>b__0(Object _)
System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
System.Threading.ThreadPoolWorkQueue.Dispatch()
System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
Bas Bossink
  • 9,388
  • 4
  • 41
  • 53

2 Answers2

3

I have had a look at your GitHub repository and it looks like you just added the package Caliburn.Micro.ReactiveUI. It means that you just have ReactiveUI core and your are missing the platform specific extensions. If you add the package reactiveui-xaml, everything works better (you will still need to initialize that messageBoxService though!).

Damien Chaib
  • 401
  • 3
  • 14
  • Thanks that fixes everything. Should `ReactiveUI-Xaml` be a dependency of `Caliburn.Micro.ReactiveUI`? – Bas Bossink Jan 07 '14 at 10:28
  • Yes, almost certainly – Ana Betts Jan 08 '14 at 03:56
  • `ReactiveUI-Xaml` is not a technical dependency of `Caliburn.Micro.ReactiveUI`, but it could make sense to add a dependency... To be honest, I am not sure what each package of `ReactiveUI` is exactly for. @PaulBetts, would you care to explain the differences? Thanks! – Damien Chaib Jan 08 '14 at 15:55
  • Many of the RxUI packages are left there for backwards compat reasons (i.e. are now just metapackages), so people aren't broken. The ones you actually should care about are ReactiveUI-Core and ReactiveUI-Platforms – Ana Betts Jan 09 '14 at 01:10
  • Thanks, that's what I had guessed... So, the remaining question is: does it make sense to reference ReactiveUI-Platforms in a package that doesn't need it just because the application will need it? What is strange is that I have had the exact opposite request from Calibrun.Micro's team to just reference Caliburn.Micro.Core in the package (https://github.com/dchaib/Caliburn.Micro.ReactiveUI/issues/14)... – Damien Chaib Jan 09 '14 at 20:01
  • I just made the same mistake. I let resharper add the reference to a missing ReactiveUI package. ( Seemed helpful at the time ). But it added only a sub package not the main reactiveui package. Then I started getting threading errors that made no sense till I found this answer. – bradgonesurfing Jun 05 '14 at 14:17
0

Your problem is that you're changing Progress in your RegisterAsyncAction, which explicitly guarantees that it won't be run on the UI thread. Here's a better way you could do this:

ObservableAsPropertyHelper<int> _progress;
public int Progress 
{
    get { return _progress.Value; }
}

public ShellViewModel(IMessageBoxService messageBoxService)
{
    DisplayCommand = new ReactiveCommand(this.WhenAny(x => x.PersonName, x => !string.IsNullOrEmpty(x.Value)));
    DisplayCommand.Subscribe(_ => messageBoxService.ShowMessageBox("You clicked on DisplayCommand: Name is " + PersonName));

    var progress = new Subject<int>();
    progress.ToProperty(this, x => x.Progress, out _progress);

    StartAsyncCommand = new ReactiveCommand();
    StartAsyncCommand.RegisterAsyncAction(_ =>
    {
        var currentProgress = 0;
        progress.OnNext(currentProgress);
        while (currentProgress <= 100)
        {
            progress.OnNext(currentProgress += 10);
            Thread.Sleep(100);
        }
    });
}

In this case, you're using the guarantee of ToProperty that it handles marshaling to the UI thread for you

Ana Betts
  • 73,868
  • 16
  • 141
  • 209
  • Thanks for the explanation, apparently my question was not explicit enough, but I get the exception for both the DisplayCommand and the StartAsyncCommand. I've updated the question to make that more clear, do you have any suggestions for the DisplayCommand? – Bas Bossink Dec 20 '13 at 06:54
  • I'm unable to get your code to compile: `System.Reactive.Subjects.Subject` does not contain a definition for `ToProperty` and the best extension method overload `ReactiveUI.OAPHCreationHelperMixin.ToProperty(System.IObservable, TObj, System.Linq.Expressions.Expression>, out ReactiveUI.ObservableAsPropertyHelper, TRet, System.Reactive.Concurrency.IScheduler)` has some invalid arguments. – Bas Bossink Dec 20 '13 at 21:46
  • Oops, change the 'ref' to an 'out' – Ana Betts Dec 20 '13 at 22:21
  • Done that, problem remains, I've updated the question with the stacktraces, and put the project on [GitHub](https://github.com/basbossink/caliburn.micro.reactiveui.sample). – Bas Bossink Dec 20 '13 at 22:55