Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wpf Decimals Styling

Tags:

wpf

I want to Style a TextBox with decimal places like this:

enter image description here

How can I do that ?

like image 913
Juan Pablo Gomez Avatar asked Jul 27 '26 05:07

Juan Pablo Gomez


1 Answers

You can extend the TextBox like this.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

public class DecimalTextBox : TextBox
{
    public static readonly DependencyProperty FloatColorProperty = DependencyProperty.Register("FloatColor", typeof(Color), typeof(DecimalTextBox), new FrameworkPropertyMetadata(Colors.Red));
    public Color FloatColor
    {
        get { return (Color)GetValue(FloatColorProperty); }
        set { SetValue(FloatColorProperty, value); }
    }

    protected TextBlock _textBlock;
    protected FrameworkElement _textBoxView;

    public DecimalTextBox()
    {
        _textBlock = new TextBlock() { Margin = new Thickness(1, 0, 0, 0) };
        Loaded += ExTextBox_Loaded;
    }

    private void ExTextBox_Loaded(object sender, RoutedEventArgs e)
    {
        Loaded -= ExTextBox_Loaded;

        // hide the original drawing visuals, by setting opacity on their parent
        var visual = this.GetChildOfType<DrawingVisual>();
        _textBoxView = (FrameworkElement)visual.Parent;
        _textBoxView.Opacity = 0;

        // add textblock to do the text drawing for us
        var grid = this.GetChildOfType<Grid>();
        if (grid.Children.Count >= 2)
            grid.Children.Insert(1, _textBlock);
        else
            grid.Children.Add(_textBlock); 
    }

    protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
    {
        base.OnLostKeyboardFocus(e);

        _textBoxView.Opacity = 0;
        _textBlock.Visibility = Visibility.Visible;
    }

    protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
    {
        base.OnGotKeyboardFocus(e);

        _textBoxView.Opacity = 1;
        _textBlock.Visibility = Visibility.Collapsed;
    }

    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        base.OnTextChanged(e);

        // making sure text on TextBlock is updated as per TextBox
        var dotPos = Text.IndexOf('.');
        var textPart1 = dotPos == -1 ? Text : Text.Substring(0, dotPos + 1);
        var textPart2 = (dotPos == -1 || dotPos >= (Text.Length-1)) ? null : Text.Substring(dotPos + 1);

        _textBlock.Inlines.Clear();
        _textBlock.Inlines.Add(new Run {
            Text = textPart1,
            FontFamily = FontFamily,
            FontSize = FontSize,
            Foreground = Foreground });

        if (textPart2 != null)
            _textBlock.Inlines.Add(new Run {
                Text = textPart2,
                FontFamily = FontFamily,
                TextDecorations = System.Windows.TextDecorations.Underline,
                BaselineAlignment = BaselineAlignment.TextTop,
                FontSize = FontSize * 5/6,
                Foreground = new SolidColorBrush(FloatColor) });
    }
}

public static class HelperExtensions
{
    public static T GetChildOfType<T>(this DependencyObject depObj) where T : DependencyObject
    {
        if (depObj == null) return null;

        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            var child = VisualTreeHelper.GetChild(depObj, i);

            var result = (child as T) ?? GetChildOfType<T>(child);
            if (result != null) return result;
        }
        return null;
    }
}

XAML code usage

<local:DecimalTextBox FloatColor="Maroon" />

And your output should look like this:

screenshot

Update 05/17

Explanation: As you can see from the image, the DecimalTextBox displays the text in formatted mode only when its not focused.

I had initially developed the control to support formatting during edit (which can still be done by commenting the methods OnLostKeyboardFocus, and OnGotKeyboardFocus) - but because of the font-size difference the cursor positioning was getting slightly skewed, which in turn would translate to bad user experience.

cursor issue

Therefore, implemented the swap logic during GotFocus and LostFocus to fix that.

like image 181
Sharada Gururaj Avatar answered Jul 30 '26 10:07

Sharada Gururaj



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!