但最近用 C# 做数据库项目,才知道问题很严重。本来输入的合法性就应该在界面上做好限制,例如对于varchar(50) 的字段,能在界面上控制用户不能输入超过50个单字节字符,是最好不过的了。然后发现 textbox 的 MaxLength 计算的只是 Unicode 长度。
对于 Unicode ,我这里就不做描述了。设置 MaxLength 是不能很好的保证输入的合法性。因此我决定为 textbox 增加一个限制最大字节数的属性:MaxByteLength 。
建立新组件
我们先新建一个组件 TextBoxEx,继承于 TextBox ,增加一个 MaxByteLength 属性
































然后重写 WndProc ,实现输入和粘贴的时候对字节长度进行判断。 (已修正输入“.”号没有判断的问题)
protected
override
void
WndProc(
ref
Message m)
{
// 如果该属性没有设置,则允许输入
if (m_MaxByteLength == 0 )
{
base .WndProc( ref m);
return ;
}
switch (m.Msg)
{
case WM_CHAR:
int i = ( int )m.WParam;
bool isBack = (i == ( int )Keys.Back);
bool isCtr = (i == 24 ) || (i == 22 ) || (i == 26 ) || (i == 3 );
if (isBack || isCtr)
{
// 控制键不作处理
}
else
{
char c = ( char )i;
if (CheckByteLengthFlow(c.ToString()))
{
break ;
}
}
base .WndProc( ref m);
break ;
case WM_PASTE:
IDataObject iData = Clipboard.GetDataObject(); // 取剪贴板对象
if (iData.GetDataPresent(DataFormats.Text)) // 判断是否是Text
{
string text = ( string )iData.GetData(DataFormats.Text); // 取数据
if (CheckByteLengthFlow(text))
{
m.Result = (IntPtr) 0 ; // 不可以粘贴
break ;
}
}
base .WndProc( ref m);
break ;
default :
base .WndProc( ref m);
break ;
}
}
/// <summary>
/// 判断即将输入的文本长度是否溢出
/// </summary>
/// <param name="text"> 文本 </param>
/// <returns> 是否溢出 </returns>
private bool CheckByteLengthFlow( string text)
{
int len = GetByteLength(text); // 输入的字符的长度
int tlen = GetByteLength( this .Text); // 文本框原有文本的长度
int slen = GetByteLength( this .SelectedText); // 文本框选中文本的长度
return (m_MaxByteLength < (tlen - slen + len));
}
/// <summary>
/// 计算文本字节长度,区分多字节字符
/// </summary>
/// <param name="text"> 文本 </param>
/// <returns> 文本字节长度 </returns>
private int GetByteLength( string text)
{
return System.Text.Encoding.Default.GetBytes(text).Length;
}
{
// 如果该属性没有设置,则允许输入
if (m_MaxByteLength == 0 )
{
base .WndProc( ref m);
return ;
}
switch (m.Msg)
{
case WM_CHAR:
int i = ( int )m.WParam;
bool isBack = (i == ( int )Keys.Back);
bool isCtr = (i == 24 ) || (i == 22 ) || (i == 26 ) || (i == 3 );
if (isBack || isCtr)
{
// 控制键不作处理
}
else
{
char c = ( char )i;
if (CheckByteLengthFlow(c.ToString()))
{
break ;
}
}
base .WndProc( ref m);
break ;
case WM_PASTE:
IDataObject iData = Clipboard.GetDataObject(); // 取剪贴板对象
if (iData.GetDataPresent(DataFormats.Text)) // 判断是否是Text
{
string text = ( string )iData.GetData(DataFormats.Text); // 取数据
if (CheckByteLengthFlow(text))
{
m.Result = (IntPtr) 0 ; // 不可以粘贴
break ;
}
}
base .WndProc( ref m);
break ;
default :
base .WndProc( ref m);
break ;
}
}
/// <summary>
/// 判断即将输入的文本长度是否溢出
/// </summary>
/// <param name="text"> 文本 </param>
/// <returns> 是否溢出 </returns>
private bool CheckByteLengthFlow( string text)
{
int len = GetByteLength(text); // 输入的字符的长度
int tlen = GetByteLength( this .Text); // 文本框原有文本的长度
int slen = GetByteLength( this .SelectedText); // 文本框选中文本的长度
return (m_MaxByteLength < (tlen - slen + len));
}
/// <summary>
/// 计算文本字节长度,区分多字节字符
/// </summary>
/// <param name="text"> 文本 </param>
/// <returns> 文本字节长度 </returns>
private int GetByteLength( string text)
{
return System.Text.Encoding.Default.GetBytes(text).Length;
}
另外,增加一个 RealText 属性,该属性返回具有合法长度的文本, 不会截断多字节字符



















































至此,可以通过设置 MaxByteLength 来限制最大字节数了。
源代码下载: /Files/lemony/TextBoxExTest_OLD.rar