Hi peeps,

You probably know the common issue with the decimal seprator. Depending on the country, the keyboard or what your client wants (which can be variable…), the separator will be a coma or a dot (or even something else…).

In my case, the Culture is “en-US“, on a Belgian keyboard where the decimal separator should be a coma. No worries, these parameters can be changed easily.

First of all, set the CultureInfo globally for your application (in the code behind of your MainView or in my case in the MainVM.cs).

System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
var currentCulture = System.Threading.Thread.CurrentThread.CurrentCulture.Name;
var ci = new CultureInfo(currentCulture)
{
    NumberFormat = { NumberDecimalSeparator = "," },
    DateTimeFormat = { DateSeparator = "/" }
};
System.Threading.Thread.CurrentThread.CurrentCulture = ci;
System.Threading.Thread.CurrentThread.CurrentUICulture = ci;
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

Adapt the NumberDecimalSeparator and/or the DateSeparator here as well.

In the View, you can now adapt the TextBox to have something like:

<TextBox Text="{Binding Value, StringFormat={}{0:0.00}, Mode=TwoWay}" 
         PreviewTextInput="OnPreviewTextInput"/>

PreviewTextInput is an event that will be raised when you enter a new character inside the TextBox.

Now in the code behind of your View, just add this method:

private void OnPreviewTextInput(object sender, TextCompositionEventArgs e)
{
    //This method is a hack to be able to replace a dot by a coma without using the KeyPressed event

    /*
     * Valid values:
     *  1,2     -->  1,2
     *  -1,2    --> -1,2
     *  ,2      -->  0,2
     *  -,2     --> -0,2
     */
    
    var textBox = ((TextBox) sender);       //Get the txtBox control
    var newChar = e.Text;                   //Get the new inserted character

    if (newChar == "\r")                    //Simulate a TAB if user pressed Enter
    {
        var request = new TraversalRequest(FocusNavigationDirection.Next);
        request.Wrapped = true;
        ((TextBox)sender).MoveFocus(request);
    }

    if (newChar.Contains("."))              //Replace the new character by a coma if it's a dot
        newChar = newChar.Replace('.', ',');

    if (textBox.SelectionLength > 0)        //Clear the content of the txtBox if there is a selection
        textBox.Text = string.Empty;

    var input = textBox.Text + newChar;     //Get the full string including the new character to validate via a regex
    var pattern = string.Format("^[-]?([0-9]?)+[{0}]?([0-9]+)?$",       //http://www.regexr.com/
        Thread.CurrentThread.CurrentUICulture.NumberFormat.NumberDecimalSeparator);

    var regex = new Regex(pattern);
    var isValid = !regex.IsMatch(input);

    if (textBox.Text.Contains("."))         //Replace the coma by a dot in the existing string
        textBox.Text = textBox.Text.Replace('.', ',') + e.Text;

    if (textBox.SelectionLength == 0)       //If there is no selection, put the cursor at the end of the string
        textBox.CaretIndex = textBox.Text.Length;
    
    e.Handled = isValid;                    //If the pattern is valid then the new character can be added
}

Adapt if needed of course…

Happy coding!  🙂