C# 在NumericUpDown控件内,数字后有文本

C# 在NumericUpDown控件内,数字后有文本,c#,.net,winforms,string,numericupdown,C#,.net,Winforms,String,Numericupdown,WinForms中是否可以在NumericUpDown控件中显示文本?例如,我想显示我的numericupdown控件中的值是微安,所以它应该类似于“1 uA” 谢谢。标准控件中没有内置此类功能。但是,通过创建一个从NumericUpDown类继承的自定义控件并重写以相应地格式化数字,添加该控件相当容易 例如,您可能具有以下类定义: public class NumericUpDownEx : NumericUpDown { public NumericUpDownEx() {

WinForms中是否可以在NumericUpDown控件中显示文本?例如,我想显示我的numericupdown控件中的值是微安,所以它应该类似于“1 uA”


谢谢。

标准控件中没有内置此类功能。但是,通过创建一个从
NumericUpDown
类继承的自定义控件并重写以相应地格式化数字,添加该控件相当容易

例如,您可能具有以下类定义:

public class NumericUpDownEx : NumericUpDown
{
    public NumericUpDownEx()
    {
    }

    protected override void UpdateEditText()
    {
        // Append the units to the end of the numeric value
        this.Text = this.Value + " uA";
    }
}

或者,要获得更完整的实现,请参见以下示例项目:

我最近偶然发现了这个问题,并找到了Cody Gray令人敬畏的答案。我利用了它的优势,但最近与他回答中的一条评论产生了共鸣,他说如果后缀仍然存在,文本将无法验证。我已经为此创建了一个可能不太专业的快速修复程序

基本上,
this.Text
字段用于读取数字

一旦找到这些数字,它们就会被放入
this.Text
,但是需要一个去盎司或任何你想调用的东西来确保我们不会造成堆栈溢出

只有数字的新文本出现后,正常的
ParseEditText()
更新文本()以完成该过程

这并不是最节省资源或最有效的解决方案,但今天大多数现代计算机都应该可以完全满足这一要求

您还会注意到,我创建了一个属性,用于更改后缀,以便在编辑器中更方便地使用

public class NumericUpDownUnit : System.Windows.Forms.NumericUpDown
    {

        public string Suffix{ get; set; }

        private bool Debounce = false;

        public NumericUpDownUnit()
        {

        }

        protected override void ValidateEditText()
        {
            if (!Debounce) //I had to use a debouncer because any time you update the 'this.Text' field it calls this method.
            {
                Debounce = true; //Make sure we don't create a stack overflow.

                string tempText = this.Text; //Get the text that was put into the box.
                string numbers = ""; //For holding the numbers we find.

                foreach (char item in tempText) //Implement whatever check wizardry you like here using 'tempText' string.
                {
                    if (Char.IsDigit(item))
                    {
                        numbers += item;
                    }
                    else
                    {
                        break;
                    }
                }

                decimal actualNum = Decimal.Parse(numbers, System.Globalization.NumberStyles.AllowLeadingSign);
                if (actualNum > this.Maximum) //Make sure our number is within min/max
                    this.Value = this.Maximum;
                else if (actualNum < this.Minimum)
                    this.Value = this.Minimum;
                else
                    this.Value = actualNum; 

                ParseEditText(); //Carry on with the normal checks.
                UpdateEditText();

                Debounce = false;
            }

        }

        protected override void UpdateEditText()
        {
            // Append the units to the end of the numeric value
            this.Text = this.Value + Suffix;
        }
    }
公共类NumericUpDown单位:System.Windows.Forms.NumericUpDown
{
公共字符串后缀{get;set;}
private bool Debounce=假;
公共数字上下单元()
{
}
受保护的重写void validateditext()
{
if(!Debounce)//我必须使用去Bouncer,因为每次更新'this.Text'字段时,它都会调用此方法。
{
Debounce=true;//确保我们没有创建堆栈溢出。
string testext=this.Text;//获取放入框中的文本。
string number=“;//用于保存我们找到的数字。
foreach(试探文本中的char项)//在这里使用“试探文本”字符串实现您喜欢的任何检查向导。
{
if(字符数字(项目))
{
编号+=项目;
}
其他的
{
打破
}
}
decimal actualNum=decimal.Parse(数字、系统、全球化、数字样式、AllowReadingSign);
if(actualNum>this.max)//确保我们的数字在min/max范围内
this.Value=this.max;
否则,如果(实际值<此最小值)
this.Value=this.Minimum;
其他的
该值=实际值;
ParseEditText();//继续进行常规检查。
updateditext();
去盎司=假;
}
}
受保护的覆盖void updateItemText()
{
//将单位附加到数值的末尾
this.Text=this.Value+后缀;
}
}
请随时改进我的答案或纠正我的错误,我是一个自学成才的程序员,仍在学习。

使用答案,评论它失败的ValidateEditText,我想出了一个简单的NumericUpDownWithUnit组件。您可以按原样复制/粘贴:

using System;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Windows.Forms;

public class NumericUpDownWithUnit : NumericUpDown
{
    #region| Fields |

    private string unit = null;
    private bool unitFirst = true;

    #endregion

    #region| Properties |

    public string Unit
    {
        get => unit;
        set
        {
            unit = value;

            UpdateEditText();
        }
    }

    public bool UnitFirst
    {
        get => unitFirst;
        set
        {
            unitFirst = value;

            UpdateEditText();
        }
    }

    #endregion

    #region| Methods |

    /// <summary>
    /// Method called when updating the numeric updown text.
    /// </summary>
    protected override void UpdateEditText()
    {
        // If there is a unit we handle it ourselfs, if there is not we leave it to the base class.
        if (Unit != null && Unit != string.Empty)
        {
            if (UnitFirst)
            {
                Text = $"({Unit}) {Value}";
            }
            else
            {
                Text = $"{Value} ({Unit})";
            }
        }
        else
        {
            base.UpdateEditText();
        }
    }

    /// <summary>
    /// Validate method called before actually updating the text.
    /// This is exactly the same as the base class but it will use the new ParseEditText from this class instead.
    /// </summary>
    protected override void ValidateEditText()
    {
        // See if the edit text parses to a valid decimal considering the label unit
        ParseEditText();
        UpdateEditText();
    }

    /// <summary>
    /// Converts the text displayed in the up-down control to a numeric value and evaluates it.
    /// </summary>
    protected new void ParseEditText()
    {
        try
        {
            // The only difference of this methods to the base one is that text is replaced directly
            // with the property Text instead of using the regex.
            // We now that the only characters that may be on the textbox are from the unit we provide.
            // because the NumericUpDown handles invalid input from user for us.
            // This is where the magic happens. This regex will match all characters from the unit
            // (so your unit cannot have numbers). You can change this regex to fill your needs
            var regex = new Regex($@"[^(?!{Unit} )]+");
            var match = regex.Match(Text);

            if (match.Success)
            {
                var text = match.Value;

                // VSWhidbey 173332: Verify that the user is not starting the string with a "-"
                // before attempting to set the Value property since a "-" is a valid character with
                // which to start a string representing a negative number.
                if (!string.IsNullOrEmpty(text) && !(text.Length == 1 && text == "-"))
                {
                    if (Hexadecimal)
                    {
                        Value = Constrain(Convert.ToDecimal(Convert.ToInt32(Text, 16)));
                    }
                    else
                    {
                        Value = Constrain(Decimal.Parse(text, CultureInfo.CurrentCulture));
                    }
                }
            }
        }
        catch
        {
            // Leave value as it is
        }
        finally
        {
            UserEdit = false;
        }
    }

    /// </summary>
    /// Returns the provided value constrained to be within the min and max.
    /// This is exactly the same as the one in base class (which is private so we can't directly use it).
    /// </summary>
    private decimal Constrain(decimal value)
    {
        if (value < Minimum)
        {
            value = Minimum;
        }

        if (value > Maximum)
        {
            value = Maximum;
        }

        return value;
    }

    #endregion
}
使用系统;
利用制度全球化;
使用System.Text.RegularExpressions;
使用System.Windows.Forms;
公共类NumericUpDownWith单位:NumericUpDown
{
#区域|字段|
私有字符串单位=null;
private bool unitFirst=true;
#端区
#区域|性质|
公共字符串单元
{
get=>unit;
设置
{
单位=价值;
updateditext();
}
}
公共事业优先
{
get=>unitFirst;
设置
{
unitFirst=值;
updateditext();
}
}
#端区
#区域法|
/// 
///更新数字上下文本时调用的方法。
/// 
受保护的覆盖void updateItemText()
{
//如果有一个单元,我们自己处理,如果没有,我们留给基类处理。
if(Unit!=null&&Unit!=string.Empty)
{
如果(第一单元)
{
Text=$“({Unit}){Value}”;
}
其他的
{
Text=$“{Value}({Unit})”;
}
}
其他的
{
base.updateItemText();
}
}
/// 
///在实际更新文本之前验证调用的方法。
///这与基类完全相同,但它将使用该类中的新ParseEditText。
/// 
受保护的重写void validateditext()
{
//考虑到标签单位,查看编辑文本是否解析为有效的小数
ParseEditText();
updateditext();
}
/// 
///将上下控件中显示的文本转换为数值并对其求值。
/// 
受保护的新void ParseEditText()
{
尝试
{
//这种方法与基本方法的唯一区别是直接替换文本
//使用属性文本而不是使用正则表达式。
//现在,我们知道文本框上可能只有我们提供的单元中的字符。
//因为NumericUpDown为我们处理来自用户的无效输入。
//这就是神奇发生的地方。这个正则表达式将匹配单元中的所有字符
//(因此您的单位不能有数字)。您可以更改此正则表达式
    class HexNumericUpDown2Digits : NumericUpDown
    {
        protected override void UpdateEditText()
        {
            if (Hexadecimal)
            {
                ChangingText = true;
                Text = $"0x{(int)Value:X2}";
            }
            else
            {
                base.UpdateEditText();
            }
        }
    }