TextBox本身有一个MaxLength的属性可以限制输入长度
但他计算长度的方式是不论中文字还英文字都算1码
如果要配合SQL Server的Varchar栏位做长度限制
那遇到中文字的部份就很容易出错了
因为中文字存到Varchar栏位占用的长度算2码
既然TextBox.MaxLength属性没办法达到我们的需求
那就自己重写一个TextBox控制项
并增加MaxByteLength的属性
public partial class uTextBox : TextBox
{
uint _maxByteLength = 0;
public uint MaxByteLength //用来限制输入长度,中文字长度以2码来计算
{
get { return _maxByteLength; }
set { _maxByteLength = value ; }
}
}
然后在OnKeyPress事件中
判断输入的长度是不是超过MaxByteLength设定的长度 这边要注意的是若user有选取文字的话 因为选取的文字是即将被取代掉的所以要先把那些文字的长度减去 才不会发生key不进去的囧境
protected override void OnKeyPress(KeyPressEventArgs e)
{
base .OnKeyPress(e);
if (ReadOnly) return ; //唯读不处理
if (_maxByteLength == 0) return ; //没设定MaxByteLength不处理
if ( char .IsControl(e.KeyChar)) return ; //Backspace, Enter...等控制键不处理
int textByteLength = Encoding.GetEncoding(950).GetByteCount(Text + e.KeyChar.ToString()); //取得原本字串和新字串相加后的Byte长度
int selectTextByteLength = Encoding.GetEncoding(950).GetByteCount(SelectedText); //取得选取字串的Byte长度,选取字串将会被取代
if (textByteLength - selectTextByteLength > _maxByteLength) e.Handled = true ; //相减后长度若大于设定值,则不送出该字元
}
注: Encoding.GetEncoding(950) == Encoding.GetEncoding("big5")
还有一点要注意的是
如果user是用复制贴上的方式
因为贴上的资料不会经过OnKeyPress事件检核
所以我们必须把复制的资料拦截下来后
再拆解成一个字元一个字元的传递给OnKeyPress去检核
int WM_PASTEDATA = 0x0302; //贴上资料的讯息
protected override void WndProc( ref Message m)
{
if (m.Msg == WM_PASTEDATA) //如果收到贴上资料的讯息,包括Ctrl+V, Shift+Ins和滑鼠右键选单中的贴上
SendCharFromClipboard(); //就把剪贴簿中的字串一个字元一个字元的拆开,再传给自己
else
base .WndProc( ref m);
}
int WM_CHAR = 0x0102;
private void SendCharFromClipboard(){foreach (char c in Clipboard.GetText()){Message msg = new Message();
msg.HWnd = Handle;msg.Msg = WM_CHAR;msg.WParam = (IntPtr)c;msg.LParam = IntPtr.Zero;base.WndProc(ref msg);}}