DigitTextBox (只能输入数字的TextBox)
直接写代码
public class DigitTextBox : TextBox, ISupportInitialize
{
[DllImport("user32.dll", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
[ResourceExposure(ResourceScope.None)]
public static extern bool MessageBeep(int type);
private static readonly decimal DefaultValue = decimal.Zero;
private static readonly decimal DefaultMinimum = decimal.MinValue;
private static readonly decimal DefaultMaximum = decimal.MaxValue;
private const bool DefaultHexadecimal = false;
private const int InvalidValue = -1;
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), Bindable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text
{
get => base.Text; set
{
base.Text = value;
ChangingText = false;
// 通常,“文本已更改”事件处理程序中的代码将“ ChangeingText”设置回false。
// 如果文本实际上没有更改,则事件处理程序将永远不会触发。
// 从此属性退出时,ChangeingText应该始终为false。
if (UserEdit)
{
ValidateEditText();
}
}
}
///
/// 获取或设置分配给上下控件的值。
///
[Category(nameof(Appearance)),
Bindable(true),
Description("当前值")]
public decimal Value
{
get
{
if (UserEdit)
{
ValidateEditText();
}
return currentValue;
}
set
{
if (value != currentValue)
{
if (!initializing && ((value < minimum) || (value > maximum)))
{
throw new ArgumentOutOfRangeException("Value", $"值必须在{minimum}-{maximum}之间");
}
else
{
currentValue = value;
OnValueChanged(EventArgs.Empty);
currentValueChanged = true;
UpdateEditText();
}
}
}
}
public bool userEdit;
///
/// 获取或设置一个值,该值指示用户是否输入了值。
///
protected bool UserEdit
{
get
{
return userEdit;
}
set
{
userEdit = value;
}
}
//////////////////////////////////////////////////////////////
// 成员变量
//////////////////////////////////////////////////////////////
// 最小值和最大值
private decimal minimum = DefaultMinimum;
private decimal maximum = DefaultMaximum;
// 内部存储当前值
private decimal currentValue = DefaultValue;
private bool currentValueChanged;
public bool ChangingText { get => changingText; private set => changingText = value; }
// onValueChanged事件的事件处理程序
private event EventHandler ValueChanged = null;
// 初始化控件时禁用值范围检查
private bool initializing = false;
private bool changingText;
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
NumberFormatInfo numberFormatInfo = System.Globalization.CultureInfo.CurrentCulture.NumberFormat;
string decimalSeparator = numberFormatInfo.NumberDecimalSeparator;
string groupSeparator = numberFormatInfo.NumberGroupSeparator;
string negativeSign = numberFormatInfo.NegativeSign;
string keyInput = e.KeyChar.ToString();
if (char.IsDigit(e.KeyChar))
{
// 数字
}
else
if ((keyInput.Equals(decimalSeparator) && !Text.Contains(decimalSeparator))
|| (keyInput.Equals(groupSeparator) && !(Text.Length > 0 && Text.LastOrDefault().ToString() == (groupSeparator)))
|| (keyInput.Equals(negativeSign) && !Text.Contains(negativeSign) && SelectionStart == 0))
{
// 小数点分隔符/负号
}
else if (e.KeyChar == '\b')
{
// 退格键
}
else if ((ModifierKeys & (Keys.Control | Keys.Alt)) != 0)
{
// 让编辑控件处理控件和alt组合键
}
else
{
// 吃掉这个无效的键并发出哔声
e.Handled = true;
MessageBeep(0);
}
}
protected void UpdateEditText()
{
// 如果要初始化,我们还不想更新编辑文本,以防万一该值无效。
if (initializing)
{
return;
}
// 如果当前值是用户编辑的,则在重新格式化之前解析该值
if (UserEdit)
{
ParseEditText();
}
// 尝试设置Value属性之前,请验证用户是否没有以“-”开头的字符串,因为“-”是有效的字符,可用来以该字符开头的字符串代表负数。
if (currentValueChanged || (!string.IsNullOrEmpty(Text) &&
!(Text.Length == 1 && Text == "-")))
{
currentValueChanged = false;
ChangingText = true;
Text = GetNumberText(currentValue);
}
}
private string GetNumberText(decimal num)
{
string text;
text = num.ToString(CultureInfo.CurrentCulture);
return text;
}
protected void ParseEditText()
{
try
{
// 尝试设置Value属性之前,请验证用户是否没有以“-”开头的字符串,因为“-”是有效的字符,可用来以一个负数开头的字符串。
if (!string.IsNullOrEmpty(Text) &&
!(Text.Length == 1 && Text == "-"))
{
Value = Constrain(decimal.Parse(Text, CultureInfo.CurrentCulture));
}
}
catch
{
// Leave value as it is
}
finally
{
UserEdit = false;
}
}
private decimal Constrain(decimal value)
{
if (value < minimum)
{
value = minimum;
}
if (value > maximum)
{
value = maximum;
}
return value;
}
protected virtual void OnValueChanged(EventArgs e)
{
ValueChanged?.Invoke(this, e);
}
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
OnTextBoxTextChanged(this, e);
}
protected virtual void OnTextBoxTextChanged(object source, EventArgs e)
{
if (changingText)
{
ChangingText = false;
}
else
{
UserEdit = true;
}
}
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
if (UserEdit)
{
ValidateEditText();
}
}
private void ValidateEditText()
{
ParseEditText();
UpdateEditText();
}
public void EndInit()
{
initializing = false;
Value = Constrain(currentValue);
UpdateEditText();
}
public void BeginInit()
{
initializing = true;
}
}