Numeric text box data binding

I was recently working on a bug report which stated that users were not possible to enter decimal numbers in a text box by hand, while it was still possible to past decimals from the clipboard. Obviously, we first checked the text box implementation and the data type used for binding – it was a simple WPF TextBox with direct data binding to a double property in ViewModel.

If you want to reconstruct the problem, create a simple .NET 4.5 / 4.6 WPF project with a window with corresponding ViewModel. The ViewModel contains one bindable property of type double (let’s call it Number), while the window only consists of a TextBox with the following binding expression:

<TextBox Text="{Binding Number, UpdateSourceTrigger=PropertyChanged}" />

Technically, this should not be a problem, since WPF is capable of automatically transforming a double into a string, and vice versa. It’s worth noting that the latter – obviously – needs parsing, which is all done under the hood, but I’ll come to that in a moment.

Start the app, and you’ll notice that the text box is pre-filled with the number 0, which is the default value of the Number property. Start typing some decimal number, e.g. by placing the cursor next to 0 and typing a decimal point (. or , etc., depending on the input culture) and some other digit – the result is that the decimal sign disappears, and the 0 digit is replaced by whichever number you entered.

What happened? We can inspect this behavior in detail if we create a simple converter that does nothing, and hook it into the binding. To watch the data, set breakpoints in the Convert and ConvertBack methods:

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)
    {
        return value;
    }
}

Start the app and enter the decimal point in addition to the existing 0 digit! The ConvertBack method will be called first, since we entered something and this value must be passed back to the ViewModel property, and “0.” is passed as value – everything fine so far! Immediately afterwards, the Convert method is invoked, and a value of “0” is passed to it! What happened? To actually pass the value of “0.” to our Number property, it obviously must be parsed to match the double data type – as mentioned before, this is done automatically. However, after this step, the Number property contains a value that differs from the text box’ content (“0” vs. “0.”), so WPF thinks it should update the text box so that it shows the actual property value!

Now, if we enter another digit, say 5 (to complete the intended input of the decimal number 0.5), the same process starts again: Since the decimal point has disappeared, the text box contains the text “05”, which is automatically parsed to the number 5, which is then passed back into the text box.

Another interesting observation: Target the project to .NET 3.5, and restart the app. You’ll notice that entering decimal numbers suddenly works without any problems! Why is this?

Let’s take a look at the FrameworkCompatibilityPreferences.KeepTextBoxDisplaySynchronizedWithTextProperty property: This property can be set app-wide, and its purpose is to specify whether the process described above (the permanent synchronisation of a text box’ content to the binding property) should be turned on or off. The MSDN page states that If your app targets WPF 4.0 or earlier, the default is false. If your app targets WPF 4.5, the default is true.

I have no idea why Microsoft decided to change this default behavior, but the solution for our problem is obvious: Set KeepTextBoxDisplaySynchronizedWithTextProperty to false in the App’s constructor, and you’ll be able to use decimal numbers as usual:

System.Windows.FrameworkCompatibilityPreferences.KeepTextBoxDisplaySynchronizedWithTextProperty = false;