|
|
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
|
|
|
|
|
Nice but I think CTRL + V doesn't work (Shift + Ins yes).
I write this code in NumericTextBox_KeyDown
if ( e.KeyChar == 22 )
{
//CTRL + V
SetNumberFromClipboard();
SelectAll();
}
after
//Prevent other keys than numeric and ,
string ls_AllowedKeyChars = "1234567890" + DecimalSeperator;
drJoju
|
|
|
|
|
Excellent job, Thanks!
|
|
|
|
|
Did this happen at your side ? Or I misuse it?
|
|
|
|
|
Hello guys,
I had the same problem. Every time a comma appears, the cursor position is 1 space before it should be.
E.g. When I enter 1, 2, 3, 4 and 5,
1,2,3 will come up fine with the curosr at the end of 3.
When I enter 4....1,234 is displayed but the cursor is now between 3 & 4
Now when I enter 5, it comes up between 3 & 4...so the result is 12354
If I continue, entering 1-9 will come up as follows:
123,568,974
Has anyone found a fix to this problem?
Any help would be really appreciated!
Cheers.
|
|
|
|
|
Locate the following code:
//if ( the position was before the comma
//then put again before the comma
if (!(ii_ScaleOnFocus == 0) )
(line 451 in my source)
replace the else part:
else
{
this.SelectionStart = this.Text.Length;
//this.SelectionStart = li_SelStart;
}
Hope this helps...
|
|
|
|
|
I just referred someone to your article. Looks like you've done some nice work here!
Mind if I add your control to the collection of control extensions that I offer with MyXaml (an open source project)?
Marc
Microsoft MVP, Visual C#
MyXaml
MyXaml Blog
Hunt The Wumpus
RealDevs.Net
|
|
|
|
|
Go right ahead. But be aware that the control doesn't support pasting numeric data, yet!
Shorty
|
|
|
|
|
this is used in windows form.another version can be used in web form?
|
|
|
|
|
Tried to "add" to the Toolbox: browsed for your dll and it showed up OK in the list of .NET components. Checked the box to select. At this point your component should have appeared. It didn't.
With no object on the form in Design View, properties don't show up.
Yes, it looks like I can create a numericTextBox1 in code, but what good is that?
Your source code should have included source for the demo program so I could figure out how to get this running!
What's the fix for this?
Alan
|
|
|
|
|
did you try to paste some text value to your control ??
:P
|
|
|
|
|
I'll try and look into it this week and post updated code...
So no i didn't
Shorty
|
|
|
|
|