Search code examples
c#wpfstring-formatting

Add $ sign in starting and end of textbox as well as format value as comma separated(thousand separated) values in textbox WPF C#


What I have tried : I am able to achieve both scenarios separately but only one works if adding the code together on the TextChanged event.

1)Add $sign in starting and ending of text as user types in Textbox code:

private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            string symbol = "$"; 
            if (TB.Text != "" && !TB.Text.StartsWith("$"))
            {
                var selectionIndex = TB.SelectionStart;
                TB.Text = TB.Text.Insert(selectionIndex, symbol);
                TB.SelectionStart = selectionIndex + symbol.Length;
            }
        }

2)Formatting comma-separated(thousand separators)values as user types in textbox code:

 private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            var TB = sender as TextBox;
            string textValue = TB.Text.Replace(",", "");
            if (double.TryParse(textValue, out result))
            {
                TB.TextChanged -= TextBox_TextChanged;
                TB.Text = string.Format("{0:#,#}", result);
                TB.SelectionStart = TB.Text.Length;
                TB.TextChanged += TextBox_TextChanged;
            }
      }

Desired Output - $3,333.55$ Decimal point getting dynamically 2, 3, 4 decimals like $4,566.444$, $3,3,456.33$ and so on


Solution

  • This is a simple string handling task:

    private int DecimalPlaces { get; set; } = 3;
    private char Delimiter { get; set; } = '$';
    
    private void TextBox_TextInput(object sender, EventArgs e)
    {
      var textBox = sender as TextBox;
      var plainInput = textBox.Text.Trim(this.Delimiter);  
      if (plainInput.EndsWith(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator))
      {
        return;
      }
    
      if (double.TryParse(plainInput, NumberStyles.Number, CultureInfo.CurrentCulture, out double number))
      {
        var decimalPlacesFormatSpecifier = GetNumberFormatSpecifier(this.DecimalPlaces);
        textBox.Text = $"{this.Delimiter}{number.ToString(decimalPlacesFormatSpecifier, CultureInfo.CurrentCulture)}{this.Delimiter}";
      }
    }
    
    private string GetNumberFormatSpecifier(int decimalPlaces)
    {
      var specifierBuilder = new StringBuilder("#,#");
      if (decimalPlaces < 1)
      {
        return specifierBuilder.ToString();
      }
    
      specifierBuilder.Append(".");
      for (int count = 0; count < decimalPlaces; count++)
      {
        specifierBuilder.Append("#");
      }
      return specifierBuilder.ToString();
    }
    

    To make the above solution robust, you must validate the input:

    • ensure that the user can only input numbers and
    • ensure that the caret can't be moved before the leading '$' and after the trailing '$'. To accomplish this you have to track the caret position.