Signum
Signum

Reputation: 885

ReactiveUI - how to manage ReactiveCommand exceptions?

I have simple user control with a ViewModel and a ReactiveCommand CheckForUpdates which runs in background and may throw. This command is explicitly executed in ViewModel's WhenActivated method. All I want to achieve is to catch the exception and log it in ViewModel, and additionally show Message Box to the user. The problem is, when I add Catch, then ThrownExceptions doesn't return anything and the MessageBox is not shown. When I remove Catch, the application crashes... I don't know how to do this properly??

public partial class SettingsDialog : SettingsDialogBase, IDialog
{
    public SettingsDialog()
    {
        InitializeComponent();

        this.WhenActivated((CompositeDisposable d) =>
        {
            ViewModel
                .CheckForUpdates
                .ThrownExceptions
                .Subscribe(ex =>
                {
                    MessageBoxHelper.ShowError(ex); // doesn't fire when `Catch` is present in ViewModel
                })
                .DisposeWith(d);
        });
    }
}



ViewModel:

public ReactiveCommand<Unit, ApplicationUpdateInfo> CheckForUpdates { get; set; }

public SettingsDialogViewModel(IApplicationUpdateService updateService)
{
    CheckForUpdates = ReactiveCommand.CreateFromTask(async () =>
    {
        return await CheckForUpdatesAsync();
    });

    this.WhenActivated((CompositeDisposable d) =>
    {
        CheckForUpdates
            .Execute()
            .Catch(Observable.Return(new ApplicationUpdateInfo())) // crashes the app if removed
            .Subscribe()
            .DisposeWith(d);
    });
}

    private async Task<ApplicationUpdateInfo> CheckForUpdatesAsync()
    {
        throw new Exception("Error");
    }

Upvotes: 0

Views: 384

Answers (1)

mm8
mm8

Reputation: 169420

You should subscribe to ThrownExceptions before the exception is thrown.

You typically do this in the constructor of the view model:

CheckForUpdates.ThrownExceptions.Subscribe(ex => ...);

If you want to subscribe to ThrownExceptions in the view, you need to do it before the view model throws, e.g.:

var subscription = ViewModel?.
    CheckForUpdates.
    ThrownExceptions.
    Subscribe(ex => MessageBoxHelper.ShowError(ex));

this.WhenActivated((CompositeDisposable d) =>
    subscription.DisposeWith(d));

Upvotes: 1

Related Questions