1
votes

In a WinForms ReactiveUI ViewModel I have a property with a property setter that can throw an ArgumentException:

public string Foo
    {
        get { return _foo; }
        set
        {
            if (value == "ERR" ) throw new ArgumentException("simulate an error");
            this.RaiseAndSetIfChanged(ref _foo, value);
            Debug.WriteLine(string.Format("Set Foo to {0}", _foo));
        }
    } 
 private string _foo;

In View the property Foo is bind to a textbox uiFoo:

this.Bind(ViewModel, vm => vm.Foo, v => v.uiFoo.Text);

Binding works properly (as shown by the output of the setter’s Debug.WriteLine). But after typing “ERR” which throws ArgumentException the binding no longer works.

What solution do I have to bring back (or keep) binding in working state after the exceptions in setter ?

1
You might try to catch and handle the exception somewhere before it hits the uppermost layers of the framework. How can a setter normally raise an exception? - Uwe Allner
I'd recommend against throwing exceptions in a setter. If a value is invalid the setter should just return, without setting the value to the backing field - Jon G Stødle
Throwing exceptions from a setter is a bad pattern. docs.microsoft.com/en-us/dotnet/standard/design-guidelines/… - Geoffrey Huntley
X AVOID throwing exceptions from property getters.+ Property getters should be simple operations and should not have any preconditions. If a getter can throw an exception, it should probably be redesigned to be a method. Notice that this rule does not apply to indexers, where we do expect exceptions as a result of validating the arguments. - Geoffrey Huntley

1 Answers

0
votes

As we've mentioned in the comments on your question, exceptions inside property getter or setters is a BIG NO, NO.

Here are two solutions available to you: Either handle the invalid value when you try to read it or use a setter method. I would much prefer the latter; especially as you're throwing an ArgumentException, which should only be used when arguments are supplied. (Breaking this rule might be confusing for the consumer of the code: "Why am I getting an ArgumentException when I'm not calling any functions?")

Here's a way to do it:

public string Foo { get; private set; }

public void SetFoo(string value)
{
    if(value == "invalid value")
        thrown new ArgumentException($"{nameof(Foo)} can't be set to '{value}'", nameof(value));

    Foo = value;
}