0

I am creating a WPF application where one of the field is UnitCost which is a property in a class. I have implemented INotifyPropertyChanged on the class which holds this property. I have a validation logic which throws an exception when the UnitCost is less than 0. I also have made use of ValidatesOnExceptions and NotifyOnValidationError attributes both set to true. Now when I change the textbox which is internally bind to UnitCost property from UI and input negative values a red adorner is displayed. However I have a flow in my application which changes the UnitCost from code behind. In this case I am not seeing any red adorner and my application crashes. I am not able to get why the application behaves in different ways when I directly change the UnitCost from UI and when I change it from code behind. Sample code:

public class Product : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private decimal unitCost;
        public decimal UnitCost
        {
            get { return unitCost; }
            set
            {
                if (value < 0)
                {
                    throw new ArgumentException("Unitcost cannot be negative");
                }

                unitCost = value;
                OnPropertyChanged("UnitCost");
            }
        }
    }

In wpf window

 <TextBox x:Name="txtUnitCost" Margin="5" Grid.Row="2" Grid.Column="1" Text="{Binding UnitCost, ValidatesOnExceptions=True, NotifyOnValidationError=True}">
            </TextBox>

Sample application window

Now when I change the Unit cost from the textbox beside the Change Unit code button application crashes. Code behind is:

 private void ChangeUnitCostHandler(object sender, RoutedEventArgs e)
        {
            var product = (Database.Product)gridProductDetails.DataContext;
            decimal cost;
            decimal.TryParse(txtUnitCostChange.Text, out cost);
            product.UnitCost = cost;
        }

While debugging it goes till throw statement, throws exception and application crashes. I am not able to find the reason why it behaves differently even if same UnitCost property is change once from UI directly from the Unit Cost text box and once from code behind.

  • 1
    Setting `product.UnitCost` calls the setter in the view model, which throws an ArgumentException that you don't catch. When you enter text in the TextBox, the exception is caught by the Binding. Try `txtUnitCost.Text = txtUnitCostChange.Text;` instead of `product.UnitCost = cost;` – Clemens May 13 '20 at 17:40
  • Binding intercepts exception thanks to [ValidatesOnExceptions](https://learn.microsoft.com/en-us/dotnet/api/system.windows.data.binding.validatesonexceptions) property. It is convenient when you try to input invalid value, e.g some string for numeric property, and exceptions occurs on update. However I don't think it is optimal to throw exceptions from viewmodel setters - you should better implement validation – ASh May 13 '20 at 17:40
  • @Clemens So as per you when I change it from code behind the WPF system knows that the change is not from binding and from alternate source i.e. code behind so it just treats the exception as unhandled exception. Is it correct. – SwapnilGhodke May 13 '20 at 17:50
  • 1
    The exception is caught by the binding and turned into a validation error. Binding validation is triggered in a `TwoWay` or `OneWayToSource` scenario. Effectively validation is triggered when data is sent from binding target to source. This means setting the property directly bypasses the binding and the validation mechanism. The property just throws an uncaught exception. As suggested, you should implement `INotifyDatsErrorInfo` for proper validation. Exceptions have a huge impact on performance and should be avoided when possible. – BionicCode May 13 '20 at 18:06
  • 1
    [How to add validation to view model properties or how to implement INotifyDataErrorInfo](https://stackoverflow.com/a/56608064/3141792) – BionicCode May 13 '20 at 18:07

0 Answers0