Click here to Skip to main content
15,892,059 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I am new to WPF. I have a requirement that I need to develop a custom textbox control which should support the functionality like:

Should accept only decimal values.

Should round off to 3 decimal places when assigned a value through code or by the user.

Should show the full value(without formatting) on focus.

Eg:

If 2.21457 is assigned to textbox(by code or by user), it should display 2.215. When user clicks in it to edit it, it must show the full value 2.21457. After the user edits the value to 5.42235 and tabs out, it should again round off to 5.422.

Tried it without success. So need some help on it. Thanks in advance for the help.

Thanks

[Edit - Kenneth Haugland]
Hey, Sorry for the late reply. I tried creating a custom control. It does contain some drawbacks but working on it.

C#
class TextBoxEx:TextBox
{
    public string ActualText
    {
        get { return (string)GetValue(ActualTextProperty); }
        set { SetValue(ActualTextProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ActualText.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ActualTextProperty =
        DependencyProperty.Register("ActualText", typeof(string), typeof(TextBoxEx), new PropertyMetadata(string.Empty, OnActualTextChanged));

    private static void OnActualTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        TextBox tx = d as TextBox;
        tx.Text = (string)e.NewValue;
        string str = tx.Text;            
        double dbl = Convert.ToDouble(str);
        str = string.Format("{0:0.###}", dbl);
        tx.Text = str;
    }

    public TextBoxEx()
    {
        this.GotFocus += TextBoxEx_GotFocus;
        this.LostFocus += TextBoxEx_LostFocus;
        this.PreviewTextInput += TextBoxEx_PreviewTextInput;
    }

    void TextBoxEx_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
    {
        decimal d;
        if(!decimal.TryParse(e.Text,out d))
        {
            e.Handled = true;
        }
    }        

    void TextBoxEx_LostFocus(object sender, System.Windows.RoutedEventArgs e)
    {
        ConvertText();
    }

    void TextBoxEx_GotFocus(object sender, System.Windows.RoutedEventArgs e)
    {
        this.Text = ActualText;
    }

    private void ConvertText()
    {
        string str = this.Text;
        ActualText = str;
        double dbl = Convert.ToDouble(str);
        str = string.Format("{0:0.###}", dbl);
        this.Text = str;
    }
}

[/Edit]
Posted
Updated 3-Mar-15 2:17am
v2
Comments
Sergey Alexandrovich Kryukov 21-Feb-15 2:44am    
What have you tried so far?
—SA

You can handle this event: https://msdn.microsoft.com/en-us/library/system.windows.uielement.previewtextinput%28v=vs.110%29.aspx[^].

The event is cancellable so you can cancel input if the user is trying to input something wrong. Please see this review: https://msdn.microsoft.com/en-us/library/ms754010%28v=vs.110%29.aspx[^].

Now, you should allow decimal point and digits. To find out if some character is digit, you can use https://msdn.microsoft.com/en-us/library/7f0ddtxh%28v=vs.110%29.aspx[^].

To find out if a character is '.', you should not hard-code it. Instead, it's better to compare a character with the decimal separator for current culture: https://msdn.microsoft.com/en-us/library/system.globalization.numberformatinfo.numberdecimalseparator%28v=vs.110%29.aspx[^].

You can always use neutral culture if you want unified format on different systems.

Also, you need to allow character with code point 8, backspace. By some reasons (historical?) this key press is treated as a character, not virtual key code.

—SA
 
Share this answer
 
v2
Hey, Sorry for the late reply. I tried creating a custom control. It does contain some drawbacks but working on it.

class TextBoxEx:TextBox
{
public string ActualText
{
get { return (string)GetValue(ActualTextProperty); }
set { SetValue(ActualTextProperty, value); }
}

// Using a DependencyProperty as the backing store for ActualText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ActualTextProperty =
DependencyProperty.Register("ActualText", typeof(string), typeof(TextBoxEx), new PropertyMetadata(string.Empty, OnActualTextChanged));

private static void OnActualTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBox tx = d as TextBox;
tx.Text = (string)e.NewValue;
string str = tx.Text;
double dbl = Convert.ToDouble(str);
str = string.Format("{0:0.###}", dbl);
tx.Text = str;
}

public TextBoxEx()
{
this.GotFocus += TextBoxEx_GotFocus;
this.LostFocus += TextBoxEx_LostFocus;
this.PreviewTextInput += TextBoxEx_PreviewTextInput;
}

void TextBoxEx_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
{
decimal d;
if(!decimal.TryParse(e.Text,out d))
{
e.Handled = true;
}
}

void TextBoxEx_LostFocus(object sender, System.Windows.RoutedEventArgs e)
{
ConvertText();
}

void TextBoxEx_GotFocus(object sender, System.Windows.RoutedEventArgs e)
{
this.Text = ActualText;
}

private void ConvertText()
{
string str = this.Text;
ActualText = str;
double dbl = Convert.ToDouble(str);
str = string.Format("{0:0.###}", dbl);
this.Text = str;
}
}
 
Share this answer
 
Comments
Kenneth Haugland 3-Mar-15 8:20am    
Use the Improve question button instead of submitting a non answer ;)
Id think I would use String Fomat to show values:
XML
<textbox name="MyTextBox" text="{Binding Path=MyValue, Mode=TwoWay, StringFormat={}{0:F2}}" />
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900