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";
}
}
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
}
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;
}
}
5条答案
按热度按时间q35jwt9p1#
标准控件中没有内置这样的功能。但是,通过创建一个自定义控件(继承自
NumericUpDown
类并重写UpdateEditText
method以相应地设置数字格式),可以很容易地添加这样的功能。例如,您可能有下列类别定义:
或者,如需更完整的实作,请参阅这个范例项目:NumericUpDown with unit measure
zu0ti5jz2#
使用CodeGray's答案、Fabio's关于它失败的注解ValidateEditText和NumericUpDown文档,我已经想出了一个简单的NumericUpDownWithUnit组件。您可以按原样复制/粘贴:
ztmd8pv53#
下面是我用来显示前缀为0x的十六进制NumericUpDown的至少2位数的代码。
bakd9h0s4#
我最近偶然发现了这个问题,并找到了Cody Gray的精彩答案。我利用了这个答案,但最近我对他的答案产生了共鸣,他说如果后缀仍然存在,文本将无法通过验证。我为此创建了一个可能不太专业的快速修复方法。
基本上,
this.Text
字段用于读取数字。一旦找到这些数字,它们就被放入
this.Text
,但是需要一个去抖动或任何你想调用它的东西,以确保我们不会创建 * 堆栈溢出 *。一旦只有数字的新文本进入,就会调用常规的
ParseEditText();
和UpdateEditText();
来完成该过程。这不是最资源友好或最有效的解决方案,但今天的大多数现代计算机应该完全没有问题。
您还会注意到,我创建了一个属性来更改后缀,以便在编辑器中更容易使用。
请随时改进我的答案或纠正我,如果有什么是错误的,我是一个自学成才的程序员仍然学习。
fcy6dtqo5#
你的动作在你的对象改变后开始,你必须从属性部分双击ValueChanged.在这个动作后你可以看到这个代码:
在//身体侧你可以写你的代码和你的控制器。就像其他人说的。