Search code examples
c#wpfxamldata-binding

DataBinding Exceptions


In wpf application I have databinding: textbox to int and double property with INPC.

Application logic must use "PropertyChanged" at UpdateSourceTrigger. Also implemented INotifyDataErrorInfo interface with data annotations attributes.

When I clear textbox I see databinding exceptions in debug output window.

System.Windows.Data Error: 7 : ConvertBack cannot convert value '' (type 'String'). BindingExpression:Path=Power; DataItem='Auto' (HashCode=64554036); target element is 'TextBox' (Name=''); target property is 'Text' (type 'String') FormatException:'System.FormatException: Input string has invalid format.
   at System.Number.ParseDouble(String value, NumberStyles options, NumberFormatInfo numfmt)
   at System.String.System.IConvertible.ToDouble(IFormatProvider provider)
   at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   at MS.Internal.Data.SystemConvertConverter.ConvertBack(Object o, Type type, Object parameter, CultureInfo culture)
   at System.Windows.Data.BindingExpression.ConvertBackHelper(IValueConverter converter, Object value, Type sourceType, Object parameter, CultureInfo culture)'

I think it's no good.

I can wrap model class (decorator pattern) and have fine validation logic in this class. Just add string properties and logic for avoid databinding exceptions.

How important is it to avoid these exceptions?

Is it should be wrapped in this case for the model class? What is the best practice for this case?

My example code with this problem.

<TextBox Text="{Binding Power, UpdateSourceTrigger=PropertyChanged}"/>
public class Auto : INotifyPropertyChanged
    {
        string _model;
        private double _power;
        private int _volume;

        public event PropertyChangedEventHandler PropertyChanged;

        private void Set<T>(ref T field, T value, [CallerMemberName]string propertyName = "")
        {
            if (EqualityComparer<T>.Default.Equals(field, value)) return;
            field = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public string Model
        {
            get => _model;
            set => Set(ref _model, value);
        }
        public double Power
        {
            get => _power;
            set => Set(ref _power, value);
        }
        public int Volume
        {
            get => _volume;
            set => Set(ref _volume, value);
        }
    }

Solution

  • How important is it to avoid these exceptions?

    Not important as the framework already handles them for you.

    Is it should be wrapped in this case for the model class?

    No, don't use string properties to hold int and double values.

    What is the best practice for this case?

    Either ignore the binding errors or implement your own converter(s):

    public class DoubleConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (!double.TryParse(value.ToString(), out double d))
                return Binding.DoNothing;
            return d;
        }
    }
    

    Usage:

    <TextBox>
        <TextBox.Text>
            <Binding Path="Power" UpdateSourceTrigger="PropertyChanged">
                <Binding.Converter>
                    <local:DoubleConverter />
                </Binding.Converter>
            </Binding>
        </TextBox.Text>
    </TextBox>