|
Hi, I am new to c# and was very excited to find this control. It does what I just need except that it doesn't allow user to leave the control unless I input a number other than 0. I can't tab away or mouse click another control.
Thanks,
|
|
|
|
|
Dear Sir,
This seems like a great control. It would be nice if it also handled decimals.
Okay, here's my bug. I have a little something in the clipboard that is invalid for the textbox:
Numeric TextBox : Allow your users to enter numeric data the easy way[^]
I noticed that your component doesn't allow the good-ol CTRL+V, however, it certainly does not block right-click, Paste. When I did that, there was an error (on the Convert.ToDecimal line). Otherwise, seems like a good go!
In Christ,
Aaron Laws
http://ProCure.com
|
|
|
|
|
failed to create component ,input string was not in correct format
saritha
|
|
|
|
|
private void testbox1_KeyPress(object sender, KeyPressEventArgs e)
{
const char Delete = (char)8;
e.Handled = !Char.IsDigit(e.KeyChar) && e.KeyChar != Delete;
}
|
|
|
|
|
I can't seem to find this anywhere in the code so when I try to add the control to my form it aborts "...Input string was not in the correct format".
Help!
Changed the following lines in NumericTextBox_TextChanged:
idec_InternalValue = Convert.ToDecimal(this.Text);
this.NumericValue = Convert.ToDecimal(this.Text);
to:
try
{
idec_InternalValue = Convert.ToDecimal(this.Text);
this.NumericValue = Convert.ToDecimal(this.Text);
}
catch (FormatException)
{
this.Text = "0";
}
|
|
|
|
|
Never mind...I had the code in the wrong place.
|
|
|
|
|
It seems there is no way to set the Text Alignment to Left in the control. It keeps moving back to Right and the code doesn't get serialized to the Designer code. Any way to fix this?
|
|
|
|
|
Comment out the line:
this.TextAlign = HorizontalAlignment.Right;
rg
|
|
|
|
|
Thanks for sharing. I find it very helpful.
|
|
|
|
|
Very good control. It has everything i wanted from NumericTextBox except pasting from clipboard.
It was very helpful, thanx.
|
|
|
|
|
how do i place (visually) the control to a Windows form ???
|
|
|
|
|
answered my own question... Controls.Add(numericTextBox1);
|
|
|
|
|
Can you modify it to add Range, Min and Max values it allows ?
Thanks
Vivek
|
|
|
|
|
Hi,
I was wondering if there is a way to load your control onto the "Toolbox->Common controls"? It would be handy to be able to drop it onto a form like a regular textbox.
And great control !!!
Neil Squires
|
|
|
|
|
As far as I know this is possible (VS2K5 and VS2K8) only if you add the control project to your solution and then build the whole.
If you just add the control's reference to the solution then you have to add the control in your code...
If anyone knows a better technique let'us know !
|
|
|
|
|
Right click on ToolBox an click 'Choose Items...'. On the '.NET Framework Components' tab, click the 'Browse...' button and select your assembly. Then you can select the controls you want to add to toolbox from the assembly. Click Ok and you're done.
|
|
|
|
|
Thanx for the control ! Indeed u have done a really good job !
But still I got a problem I cannot handle with ! An exception is thrown when I try to add it on the form at design time !
It says:
"System.FormatException was unhandled
Message="Input string was not in a correct format."
Source="mscorlib"
StackTrace:
at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseDecimal(String value, NumberStyles options, NumberFormatInfo numfmt)
at System.Decimal.Parse(String s, IFormatProvider provider)
at System.Convert.ToDecimal(String value)
at Shorty.Windows.Forms.NumericTextBox.NumericTextBox_TextChanged(Object sender, EventArgs e)
at System.Windows.Forms.Control.OnTextChanged(EventArgs e)
at System.Windows.Forms.TextBoxBase.OnTextChanged(EventArgs e)
at System.Windows.Forms.Control.set_Text(String value)
at System.Windows.Forms.TextBoxBase.set_Text(String value)
at System.Windows.Forms.TextBox.set_Text(String value)
at WinAppNumericTextBox.Form1.InitializeComponent()
at WinAppNumericTextBox.Form1..ctor()
at WinAppNumericTextBox.Form1.Main()"
Is there any way to get around with it ?
( Product Info:
Microsoft Visual Studio 2005
Version 8.0.50727.42 (RTM.050727-4200)
Microsoft .NET Framework
Version 2.0.50727
)
And one more thing that may help to fix the problem. When I Create control in a program way on my own it goes fine !
|
|
|
|
|
I got the same problem
Never underestimate capability and overestimate experience
|
|
|
|
|
This is because the designer is setting the Text property of the control to the normal text box default (e.g. textBox1) which then throws when trying to convert to decimal in NumericTextBox_TextChanged
The Text property shouldn't really be shown in designer (or should be given a sensible default), however a quick attempt at doing this didn't work, so for the moment I've changed the following lines in NumericTextBox_TextChanged:
idec_InternalValue = Convert.ToDecimal(this.Text);
this.NumericValue = Convert.ToDecimal(this.Text);
to:
try
{
idec_InternalValue = Convert.ToDecimal(this.Text);
this.NumericValue = Convert.ToDecimal(this.Text);
}
catch (FormatException)
{
this.Text = "0";
}
richard
|
|
|
|
|
|
That's an awesome control.
But I noted that the control does not accept Ctl-C, Ctrl-V and Ctrl-X. Instead, right-click context menu (Cut, Copy and Paste) is regulary accepted.
Is there a fix for this?
Thank you.
c
|
|
|
|
|
This problem occurs to me too.
Luigi
|
|
|
|
|
using System;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
namespace NumTextBox
{
[System.ComponentModel.DefaultEvent("TextBoxChanged"),
System.ComponentModel.DefaultProperty("Text"),
ToolboxBitmap(typeof(System.Windows.Forms.TextBox))]
///
/// NumTextBox 的摘要说明。
///
public class TextBoxNumEx : System.Windows.Forms.TextBox
{
///
/// 必需的设计器变量。
///
private System.ComponentModel.Container components = null;
//以下是消息号,参考WinUser.h中的申明
public const int WM_SETFOCUS = 0x0007; //得到焦点
public const int WM_KILLFOCUS = 0x0008; //失去焦点
public const int WM_CONTEXTMENU = 0x007b; //右键菜单消息
public const int WM_CHAR = 0x0102; //输入字符消息(键盘输入的,输入法输入的好像不是这个消息)
public const int WM_CUT = 0x0300; //程序发送此消息给一个编辑框或combobox来删除当前选择的文本
public const int WM_COPY = 0x0301; //程序发送此消息给一个编辑框或combobox来复制当前选择的文本到剪贴板
public const int WM_PASTE = 0x0302; //程序发送此消息给editcontrol或combobox从剪贴板中得到数据
public const int WM_CLEAR = 0x0303; //程序发送此消息给editcontrol或combobox清除当前选择的内容;
public const int WM_UNDO = 0x0304; //程序发送此消息给editcontrol或combobox撤消最后一次操作
#region 属性
private string strFormat = "G";
///
/// 数值格式
///
[System.ComponentModel.RefreshProperties(System.ComponentModel.RefreshProperties.All),
System.ComponentModel.Category("数值相关设置"),
System.ComponentModel.Description("数值格式")]
public virtual string Format
{
set
{
string format;
string strPrecision;
format = value;
decimal decTest = 325456245.021564M;
try
{
decTest.ToString(format);
}
catch(Exception)
{
format = "G"; //无效的格式时采用G
}
strFormat = format;
strPrecision = decTest.ToString(format);
//设置最大的精度
this.NumericPrecision = strPrecision.IndexOf('.') < 0 ? 0 : strPrecision.Length - strPrecision.IndexOf('.') - 1;
this.Text = this.Text;
}
get
{
return strFormat;
}
}
///
/// 当前数值格式的最大精度
///
private int NumericPrecision = 2;
private bool bZeroIsValid = true;
///
/// 0值是否显示有效
///
[System.ComponentModel.RefreshProperties(System.ComponentModel.RefreshProperties.All),
System.ComponentModel.Category("数值相关设置"),
System.ComponentModel.Description("0值是否显示有效")]
public virtual bool ZeroIsValid
{
set
{
bZeroIsValid = value;
this.Text = this.Text;
}
get
{
return bZeroIsValid;
}
}
private bool bAllowNegative = true;
///
/// 是否允许输入负数
///
[System.ComponentModel.RefreshProperties(System.ComponentModel.RefreshProperties.All),
System.ComponentModel.Category("数值相关设置"),
System.ComponentModel.Description("是否允许输入负数")]
public virtual bool AllowNegative
{
set
{
bAllowNegative = value;
if (!value)
this.Text = this.Text;
}
get
{
return bAllowNegative;
}
}
#endregion
public TextBoxNumEx()
{
InitializeComponent();
//
// TODO: 在此处添加构造函数逻辑
//
base.Text = "0";
this.SelectionStart = 0;
//目前无法找到按下Delete键的消息值,所以采用事件来处理按下Delete的情况
this.KeyDown += new KeyEventHandler(TextBoxNumEx_KeyDown);
this.KeyUp += new KeyEventHandler(TextBoxNumEx_KeyUp);
this.TextAlign = HorizontalAlignment.Right;
}
///
/// 清理所有正在使用的资源。
///
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region 控件设计器生成的代码
///
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
///
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
#region 重载的方法与属性
///
/// 重载的Text属性
///
[System.ComponentModel.DefaultValue(0)]
public override string Text
{
get
{
string strReturn = "0";
string strBaseText = base.Text;
while(strBaseText.IndexOf(',') >= 0)
{
strBaseText = strBaseText.Replace(",","");
}
if (strBaseText.Length > 0 && strBaseText.LastIndexOf('.') == strBaseText.Length - 1)
strBaseText = strBaseText.Substring(0,strBaseText.LastIndexOf('.'));
if (strBaseText == string.Empty || strBaseText == "-")
strBaseText = "0";
if (strBaseText.IndexOf('.') >= 0) //如果显示的是.0001或-.90的显示时,自动在.前面补0
if (strBaseText.Substring(0,strBaseText.IndexOf('.')) == "-" || strBaseText.Substring(0,strBaseText.IndexOf('.')) == string.Empty)
strBaseText = strBaseText.Substring(0,strBaseText.IndexOf('.')) + "0" + strBaseText.Substring(strBaseText.IndexOf('.'));
try
{
decimal.Parse(strBaseText).ToString(this.Format);
}
catch(Exception)
{
//应该不会出错!出错不处理
strBaseText = "0";
}
strReturn = strBaseText;
return strReturn;
}
set
{
decimal decValue;
if (value == null || value == string.Empty)
value = "0";
try
{
decValue = decimal.Parse(value);
}
catch(Exception)
{
//MessageBox.Show("输入的值不是有效的值或超出范围!"+ex.Message, "错误信息", MessageBoxButtons.OK, MessageBoxIcon.Warning);
try
{
decValue = decimal.Parse(this.Text);
}
catch(Exception)
{
decValue = 0;
}
}
if (decValue == 0 && !this.ZeroIsValid)
base.Text = string.Empty;
else
base.Text = decValue.ToString(this.Format);
}
}
///
/// 不允许多行显示
///
public override bool Multiline
{
get
{
return base.Multiline;
}
set
{
base.Multiline = false;
}
}
///
/// 重载消息处理
///
/// <param name="m" />
protected override void WndProc(ref Message m)
{
switch(m.Msg)
{
case WM_SETFOCUS: //得到焦点时,重新设置光标位置
if (base.Text == string.Empty)
base.Text = (0.0M).ToString(this.Format);
base.WndProc(ref m);
this.SelectionStart = 0;
break;
case WM_KILLFOCUS: //焦点移开时,重新设置显示
this.Text = base.Text;
base.WndProc(ref m);
break;
case WM_CHAR:
bool isSign = ((int)m.WParam == 45); //减号
bool isNum = ((int)m.WParam >= 48) && ((int)m.WParam <= 57); //数字
bool isBack = (int)m.WParam == (int)Keys.Back; //退格键
bool isDelete = (int)m.WParam == (int)Keys.Delete;//实际上这是一个"."键
bool isCtr = ((int)m.WParam == 24) || ((int)m.WParam == 22) || ((int)m.WParam == 26) ||((int)m.WParam == 3);
if( isNum || isBack || isCtr)
{
if (isBack)
{
//处理不能删除 .
if (this.SelectionStart == base.Text.IndexOf('.') + 1)
break;
}
if (isNum)
{
//减号前面不能输入数字
if (this.SelectionStart == 0 && base.Text.IndexOf('-') >= 0)
break;
if (base.Text.IndexOf('.') >= 0 && this.SelectionStart - base.Text.IndexOf('.') > this.NumericPrecision)
{
return;
}
}
base.WndProc (ref m);
}
if (isSign)
{
if (!this.AllowNegative) //不允许输入负数
break;
if (this.SelectionStart != 0) //当前光标不在第一位时不允许输入减号
break;
if (this.Text.IndexOf('-') < 0)
base.WndProc (ref m);
else
this.SelectionStart = 1; //第一位已经是减号时,光标重新定位
break;
}
if (isDelete && this.NumericPrecision > 0) //只有当前的精度大于0才能输入点
{
if (base.Text.IndexOf('.') < 0)
{
base.WndProc (ref m);
}
else
{
if (base.Text.IndexOf('.') < this.SelectionStart)
break;
base.Text = base.Text.Substring(0,this.SelectionStart) + "." + base.Text.Substring(base.Text.LastIndexOf('.') + 1);
this.SelectionStart = base.Text.IndexOf('.') + 1;
}
}
if ((int)m.WParam == 1)
{
this.SelectAll();
}
if (!isSign) //输入的不是 - 的话,重新格式化一次
{
bool bNegative = false; //是不是负数
string strBaseText = base.Text;
while(strBaseText.IndexOf(',') >= 0)
{
strBaseText = strBaseText.Replace(",","");
}
if (strBaseText.Length > 0 && strBaseText.LastIndexOf('.') == strBaseText.Length - 1)
strBaseText = strBaseText.Substring(0,strBaseText.LastIndexOf('.'));
if (strBaseText.Length > 0)
bNegative = strBaseText.Substring(0,1) == "-";
if (strBaseText == string.Empty || strBaseText == "-")
strBaseText = "0";
if (strBaseText.IndexOf('.') >= 0) //如果显示的是.0001或-.90的显示时,自动在.前面补0
if (strBaseText.Substring(0,strBaseText.IndexOf('.')) == "-" || strBaseText.Substring(0,strBaseText.IndexOf('.')) == string.Empty)
strBaseText = strBaseText.Substring(0,strBaseText.IndexOf('.')) + "0" + strBaseText.Substring(strBaseText.IndexOf('.'));
//如果有精度控制的话,判断是否越过了精度
if (strBaseText.IndexOf('.') >= 0)
if (strBaseText.Substring(strBaseText.IndexOf('.') + 1).Length > this.NumericPrecision)
strBaseText = strBaseText.Substring(0,strBaseText.IndexOf('.') + 1) + strBaseText.Substring(strBaseText.IndexOf('.') + 1, this.NumericPrecision);
try
{
strBaseText = decimal.Parse(strBaseText).ToString(this.Format);
}
catch(Exception)
{
//应该不会出错!出错不处理
}
if (bNegative && strBaseText.Length > 0)
{
if (strBaseText.Substring(0,1) != "-")
strBaseText = "-" + strBaseText;
}
//记录光标位置。小数点左边显示正数,否则显示负数,整数以长度为小数点位置
int iCursorPosition = base.Text.IndexOf('.') >= 0 ? base.Text.IndexOf('.') - this.SelectionStart : base.Text.Length - this.SelectionStart;
//设置显示时先清空显示,然后再加载.否则会显示不正确
base.Text = string.Empty;
base.Text = strBaseText;
//重新定位
this.SetCursorPosition(iCursorPosition);
}
break;
case WM_PASTE:
IDataObject iData = Clipboard.GetDataObject();//取剪贴板对象
if(iData.GetDataPresent(DataFormats.Text)) //判断是否是Text
{
bool bNegative = false;
string str = (string)iData.GetData(DataFormats.Text);//取数据
//取消空格
str = str.Trim();
if (MatchNumber(str))
{
string strBaseText = str;
while(strBaseText.IndexOf(',') >= 0)
{
strBaseText = strBaseText.Replace(",","");
}
if (strBaseText.Length > 0 && strBaseText.LastIndexOf('.') == strBaseText.Length - 1)
strBaseText = strBaseText.Substring(0,strBaseText.LastIndexOf('.'));
if (strBaseText.Length > 0)
bNegative = strBaseText.Substring(0,1) == "-";
if (strBaseText == string.Empty || strBaseText == "-")
strBaseText = "0";
if (strBaseText.IndexOf('.') >= 0) //如果显示的是.0001或-.90的显示时,自动在.前面补0
if (strBaseText.Substring(0,strBaseText.IndexOf('.')) == "-" || strBaseText.Substring(0,strBaseText.IndexOf('.')) == string.Empty)
strBaseText = strBaseText.Substring(0,strBaseText.IndexOf('.')) + "0" + strBaseText.Substring(strBaseText.IndexOf('.'));
try
{
strBaseText = decimal.Parse(strBaseText).ToString(this.Format);
}
catch(Exception)
{
//应该不会出错!出错不处理
}
if (bNegative && strBaseText.Length > 0)
{
if (strBaseText.Substring(0,1) != "-")
strBaseText = "-" + strBaseText;
}
//设置显示时先清空显示,然后再加载.否则会显示不正确
base.Text = string.Empty;
base.Text = strBaseText;
this.SelectionStart = 0;
break;
}
}
m.Result = (IntPtr)0;//不可以粘贴
break;
default:
base.WndProc (ref m);
break;
}
}
///
/// 由于消息处理中无法得到Delete的消息。所以采用事件处理按下Delete键执行了删除后显示的问题
///
/// <param name="sender" />
/// <param name="e" />
private void TextBoxNumEx_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Delete)
{
if (this.SelectionStart == base.Text.IndexOf('.'))
e.Handled = true;
}
}
///
/// 由于消息处理中无法得到Delete的消息。所以采用事件处理按下Delete键执行了删除后显示的问题
///
/// <param name="sender" />
/// <param name="e" />
private void TextBoxNumEx_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Delete) //按删除时执行
{
bool bNegative = false;
string strBaseText = base.Text;
while(strBaseText.IndexOf(',') >= 0)
{
strBaseText = strBaseText.Replace(",","");
}
if (strBaseText.Length > 0 && strBaseText.LastIndexOf('.') == strBaseText.Length - 1)
strBaseText = strBaseText.Substring(0,strBaseText.LastIndexOf('.'));
if (strBaseText.Length > 0)
bNegative = strBaseText.Substring(0,1) == "-";
if (strBaseText == string.Empty || strBaseText == "-")
strBaseText = "0";
if (strBaseText.IndexOf('.') >= 0) //如果显示的是.0001或-.90的显示时,自动在.前面补0
if (strBaseText.Substring(0,strBaseText.IndexOf('.')) == "-" || strBaseText.Substring(0,strBaseText.IndexOf('.')) == string.Empty)
strBaseText = strBaseText.Substring(0,strBaseText.IndexOf('.')) + "0" + strBaseText.Substring(strBaseText.IndexOf('.'));
try
{
strBaseText = decimal.Parse(strBaseText).ToString(this.Format);
}
catch(Exception)
{
//应该不会出错!出错不处理
}
if (bNegative && strBaseText.Length > 0)
{
if (strBaseText.Substring(0,1) != "-")
strBaseText = "-" + strBaseText;
}
//记录光标位置
//记录光标位置。小数点左边显示正数,否则显示负数,整数以长度为小数点位置
int iCursorPosition = base.Text.IndexOf('.') >= 0 ? base.Text.IndexOf('.') - this.SelectionStart : base.Text.Length - this.SelectionStart;
//设置显示时先清空显示,然后再加载.否则会显示不正确
base.Text = string.Empty;
base.Text = strBaseText;
//重新定位
this.SetCursorPosition(iCursorPosition);
}
}
#endregion
#region 方法
protected virtual bool MatchNumber(string ClipboardText)
{
int index = 0;
string strNum = "-0.123456789,";
if (ClipboardText.Length == 0)
return false;
if (ClipboardText == "-" || ClipboardText == "." || ClipboardText == ",")
return false;
index = ClipboardText.IndexOf(strNum[0]);
if (index >= 0)
{
if (index > 0)
{
return false;
}
}
index = ClipboardText.IndexOf(strNum[2]);
if (index != -1 && index != ClipboardText.Length - 1)
{
index = ClipboardText.IndexOf(strNum[2], index + 1);
if (index != -1)
{
return false;
}
}
for(int i = 0; i < ClipboardText.Length; i++)
{
index = strNum.IndexOf(ClipboardText[i]);
if (index < 0)
{
return false;
}
}
return true;
}
///
/// 重新设置光标位置
///
/// <param name="iCursorPosition" />原先的光标位置
private void SetCursorPosition(int iCursorPosition)
{
if (iCursorPosition < 0) //光标在小数点的右边
{
if (base.Text.IndexOf('.') < 0)
this.SelectionStart = base.Text.Length;
else
this.SelectionStart = System.Math.Abs(base.Text.IndexOf('.') - iCursorPosition);
}
else //光标在小数点的左边
{
if (base.Text.IndexOf('.') < 0)
this.SelectionStart = base.Text.Length - iCursorPosition;
else
this.SelectionStart = System.Math.Abs(base.Text.IndexOf('.') - iCursorPosition);
}
}
#endregion
}
}
bys_home
|
|
|
|
|
Very nice component but;
when pressing Shift+Insert (old school paste) program is shutting down.
|
|
|
|
|
You have done very good job.. congratulation.
But i have a quite slight modification to make this work with copy/paste keyboard shortcuts (Ctrl-C and Ctrl-V) and also i override the default cut/copy/parte function on contextual menu.
I have added this on class start
public class NumericTextBox : TextBox { private const int WM_CUT = 0x0300; private const int WM_COPY = 0x0301; private const int WM_PASTE = 0x0302; ... ... ...
and this
private void SetNumberFromClipboard() { IDataObject myClip = Clipboard.GetDataObject(); if (myClip.GetDataPresent(DataFormats.Text)) { string myStr = (string)myClip.GetData(DataFormats.Text); try { decimal dec_temp = Convert.ToDecimal(myStr); dec_temp = Math.Round(dec_temp, Math.Max(ii_ScaleOnFocus, ii_ScaleOnLostFocus) ); int my_Precision = dec_temp.ToString().Length; if (my_Precision<= ii_Precision) { NumericValue = dec_temp; this.SelectAll(); } } catch{} finally{} } }
and this
protected override void WndProc(ref Message m) { switch(m.Msg) { case WM_CUT: //Own cut code Clipboard.SetDataObject(idec_InternalValue.ToString(),true); NumericValue = ib_ZeroNotValid ? 0:NumericValue; SelectAll(); break; case WM_COPY: //Own copy code Clipboard.SetDataObject(idec_InternalValue.ToString(),true); break; case WM_PASTE: // Own paste code SetNumberFromClipboard(); SelectAll(); break; default: base.WndProc(ref m); break; } }
And in the NumericTextBox_KeyDown:
private void NumericTextBox_KeyDown(object sender, KeyEventArgs e) { //cut if (e.KeyCode == Keys.X && e.Control) { Clipboard.SetDataObject(idec_InternalValue.ToString(),true); NumericValue = ib_ZeroNotValid ? 0:NumericValue; SelectAll(); return; } //paste if (e.KeyCode == Keys.V && e.Control) { SetNumberFromClipboard(); return; } //copy if (e.KeyCode == Keys.C && e.Control) { Clipboard.SetDataObject(idec_InternalValue.ToString(),true); return; } ... ... ...
And now it goes OK.
Claudiu
|
|
|
|
|