Search code examples
c#wpfxamlstring-formatting

How do I separate the content of a textbox by number without binding?


I want to show the numbers in TextBox with thousand separator without binding it and without programmatically.

Just in XAML.

like this example:

123456 => 123,456 or 1000000000 => 1,000,000,000

Also this line in XAML have error:

<TextBox x:Name="text_main2" Text="{Binding StringFormat={}{0:N0}}"  VerticalAlignment="Top" Width="303"/>

And I don't no can I do this work in TextBoxMask:

<xctk:MaskedTextBox Mask="0000"  PromptChar=" " x:Name="txtname"  HorizontalContentAlignment="Right" HorizontalAlignment="Left" Height="22" Margin="512,296,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="152"/>

Please help


Solution

  • You can't do it without binding or writing additional code in general. The TextBox has no build in text/input formatting.

    But in a proper WPF application you would always use data binding in order to send user input to a model that processes the input, so using Binding.StringFormat to format displayed values is a straight forward solution and quite flexible. It allows to format the displayed value without modifying the actual value (data).

    Another solution which allows to only modify the displayed value and not the actual data, is to implement an IValueConverter and assign it to Binding.Converter.

    Other options involve subclassing TextBox (like your MaskedTextBox type) or creating an attached behavior. The goal should be to format the number for display without modifying the actual value.

    To fix the error you have I suggest to fix your binding. You didn't explained what kind of error you get. But at least your Binding needs a fix.
    You can't just set the property StringFormat. This is not how MarkupExtensions work. Binding MarkupExtension has a constructor that requires a Binding.Path value (except you use the default constructor which uses the default value, which resolves to the current DataContext). You can't omit it.
    So, if you want to set a property on Bindng without specifying a Path (because you want to use the implicit binding source to the DataContex you can use the '.' (period) notation:

    {Binding} is equivalent to {Binding Path=.}.

    So to fix the binding expression it should be:

    <TextBox Text="{Binding Path=., StringFormat={}{0:N0}}" />
    

    Example

    MainWindow.xaml.cs

    public partial class MainWindow : Window
    {
      public static readonly DependencyProperty NumericValueProperty = DependencyProperty.Registe(
        "NumericValue",
        typeof(int),
        typeof(MainWindow),
        new PropertyMetadata(default(int), MainWindow.OnNumericValueChanged));
    
      public int NumericValue
      {
        get => (int) GetValue(MainWindow.NumericValueProperty);
        set => SetValue(MainWindow.NumericValueProperty, value);
      }
    
      // Property changed callbacck
      private static void OnNumericValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
        var textBox = d as TextBox;
        int newValue = (int) e.NewValue;
    
        // Do something with the new value that was entered by the user
      }
    
      public MainWindow()
      {
        InitializeComponent();
        
        // Set DataContext to the MainWindow itself
        this.DataContext = this;
    
        // We want 10000 to be displayed with thousands number groups
        // like '10.000'
        this.NumericValue = 10000;
      }
    }
    

    MainWindow.xaml

    <Window>
    
      <!-- Display number with thousands groups. Note that 'N0' will truncate decimal places (zero deimal places) -->
      <TextBox Text="{Binding NumericValue, StringFormat={}{0:N0}}" />
    </Window>
    

    Recomended read: