Custom Numericupdown

2.2k views Asked by At

I'm trying to create a custom numericUpDown control. I'm trying to add text to the numericUpDown and I got it working good. But, now I want to find a way to select only the number when clicking in the control, because at this moment when I "edit" the value manually, I can erase the unit I added into the control. I found this control in a software on google that is like a "ranged" numericUpDown. It works like the way I need, it has been possible to click and select only the numbers. When you click in the text, it should select the number to be edited and not the text:

If you click on "to" it selects the 50 that changes when you click in the "arrows"

This is what I have now:

public class RangedNumericUpDown : NumericUpDown
    {
        public int ValueMin = 0;
        public int ValueMax = 10;

        public RangedNumericUpDown()
        {

        }

        protected override void UpdateEditText()
        {
            if(this.Text != this.ValueMin + " to " + this.ValueMax)
                this.Text = this.ValueMin + " to " + this.ValueMax;
        }
    }

I couldn't find any custom control for windows forms like this, and I guess it is possible to create something like that image.

1

There are 1 answers

1
Hans Passant On BEST ANSWER

Well, you don't have enough code. Not so sure I'd recommend this, moving the "focus" from one value to another isn't exactly very intuitive. You'll get better UI from simply using two NUDs.

Anyhoo, some code to play with:

using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Globalization;

class RangeUpDown : NumericUpDown {
    public decimal LowValue { get; set; }
    public decimal HighValue { get; set; }

    private bool lowFocused = true;
    private const string separator = " to ";

    protected override void UpdateEditText() {
        if (base.UserEdit) ParseText();
        var lotext = FormatValue(LowValue);
        var hitext = FormatValue(HighValue);
        this.Text = lotext + separator + hitext;
        if (lowFocused) {
            EditBox.SelectionStart = 0;
            EditBox.SelectionLength = lotext.Length;
        }
        else {
            EditBox.SelectionStart = lotext.Length + separator.Length;
            EditBox.SelectionLength = hitext.Length;
        }
        EditBox.Focus();
    }

    public override void UpButton() {
        if (base.UserEdit) ParseText();
        if (IsLowValueFocused()) {
            LowValue = Math.Min(this.Maximum, LowValue + this.Increment);
            if (HighValue < LowValue) HighValue = LowValue;
        }
        else {
            HighValue = Math.Min(this.Maximum, HighValue + this.Increment);
        }
        this.OnValueChanged(EventArgs.Empty);
        UpdateEditText();
    }

    public override void DownButton() {
        if (base.UserEdit) ParseText();
        if (IsLowValueFocused()) {
            LowValue = Math.Max(this.Minimum, LowValue - this.Increment);
        }
        else {
            HighValue = Math.Max(this.Minimum, HighValue - this.Increment);
            if (LowValue > HighValue) LowValue = HighValue;
        }
        this.OnValueChanged(EventArgs.Empty);
        UpdateEditText();
    }

    private bool IsLowValueFocused() {
        lowFocused = EditBox.Text.Substring(EditBox.SelectionStart).Contains(separator.Trim());
        return lowFocused;
    }

    private string FormatValue(decimal value) {
        var fmt = (this.ThousandsSeparator ? "N" : "F");
        var frac = this.DecimalPlaces.ToString(CultureInfo.CurrentCulture);
        return value.ToString(fmt + frac, CultureInfo.CurrentCulture);
    }

    private TextBox EditBox { get { return (TextBox)Controls[1]; } }

    private void ParseText() {
        // Not implemented
        base.UserEdit = false;
    }
}