0
votes

I have been using ReactiveUI to create viewmodels and bind them to my WPF views. In these viewmodels I use UserError to wrap exceptions and forward them to the associated view.

However, I have noticed that when a UserError is thrown, it does not always end up in the expected handler. To fix this, I subclassed UserError and registered handlers for only this subclass using UserError.RegisterHandler<MyUserErrorSubclass>(myHandler)

This seems to work, but does not fully fix the problem. I now have two instances of the same viewmodel and associated view, but the UserError thrown in one viewmodel ends up in the wrong view. This is a problem because I want to show an error message, but it shows up in the wrong view.

Example code:

class ViewModel : ReactiveObject {
    ...
    public ReactiveCommand<object> ExampleCommand { get; }

    ViewModel(){
        ...

        ExampleCommand.ThrownExceptions.Subscribe(ex => UserError.Throw(new UserError("Error!")));
    }
}

class View : IViewFor<ViewModel> {
    ...
    Label exampleLabel;

    View(){
        ...
        UserError.RegisterHandler(userError => {
            exampleLabel.Text = userError.ErrorMessage;
        });
        ...
    }
    ...
}


ViewModel aModel = new ViewModel();
View aView = new View { ViewModel = aModel};

ViewModel bModel = new ViewModel();
View bView = new View { ViewModel = bModel};

Calling aModel.Example() sets bView.exampleLabel, while I need to set aView.exampleLabel

What is the best way to resolve this issue?

1

1 Answers

2
votes

I figured it out by looking at the ReactiveUI source code.

If you receive a UserError in a handler that cannot handle it, you are supposed to return null. The UserError will then be passed to the next registered handler.

Example code:

UserError.RegisterHandler(userError => {
    if(cannotHandleThisError){
        return null;
    }
    exampleLabel.Text = userError.ErrorMessage;
});

I subclassed UserError and stored the throwing viewmodel in the usererror. I now check whether or not the viewmodel in the error matches the handlers viewmodel before executing.