Search code examples
c#data-bindinguwpdependency-propertiesnullable

Binding Expression Error When Binding to Nullable Int32


So I think I found a really interesting bug in the UWP platform.

If I have a textbox and I bind its Text property to a int? dependency property, then I get the following exception. It doesn't seem to matter if my consumer binds a nullable int or nonnullable int to the control, the same error is displayed. It looks like it's directly related to the dependency property being nullable.

Error: Converter failed to convert value of type 'Windows.Foundation.Int32' 
to type 'IReference`1<Int32>'; BindingExpression: Path='MyNotNullableInt' 
DataItem='ControlSandbox.FooViewModel'; target element is 
'ControlSandbox.NumericTextBox' (Name='null'); 
target property is 'Value' (type 'IReference`1<Int32>'). 

I'm not even using a converter so I'm guessing this is something happening in the guts of the framework. The example code below will produce the output

Main.xaml

    <Grid Background="White" >
        <local:NumericTextBox Value="{Binding MyNotNullableInt, Mode=TwoWay}" />
    </Grid>

Main.xaml.cs

    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            this.DataContext = new FooViewModel();
        }
    }

FooViewModel.cs

  public class FooViewModel : INotifyPropertyChanged
    {
        private int _myNotNullableInt;

        public int MyNotNullableInt
        {
            get { return _myNotNullableInt; }
            set { _myNotNullableInt = value; OnPropertyChanged("MyNotNullableInt"); }
        }

        private int? _myNullableInt;

        public int? MyNullableInt
        {
            get { return _myNullableInt; }
            set { _myNullableInt = value; OnPropertyChanged("MyNullableInt"); }
        }


        public FooViewModel()
        {
            MyNullableInt = null;
        }


        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string prop)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
            }
        }
    }

NumericTextBox.xaml

    <Grid>
        <TextBox Text="{x:Bind Value}" />
    </Grid>

NumericTextBox.xaml.cs

 public sealed partial class NumericTextBox : UserControl
    {
        public int? Value
        {
            get { return (int?)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(int?), typeof(NumericTextBox), new PropertyMetadata(0));

        public NumericTextBox()
        {
            this.InitializeComponent();
        }
    }

Solution

  • So I'm not sure why this page didn't come back in our initial hours of research on the error, however, at least this post now will document this for the future.

    I was looking into binding to nullable dependency properties and I came across this article

    Turns out that under the covers most of the .NET primitive types are converted to equivalent Windows Runtime types. IReference happens to be the Windows Runtime equivalent of Nullable in .NET.

    It says, that you need to change the property type typeofon the dependency property from your nullable type to object

    I've confirmed this works.

    public static readonly DependencyProperty ValueProperty =
                DependencyProperty.Register("Value", typeof(object), typeof(NumericTextBox), new PropertyMetadata(0));