用于文本框过滤的通用基类





4.00/5 (6投票s)
2007 年 3 月 20 日
5分钟阅读

45318

699
本文描述了一个基类 FilterTextBox,它可用于为 TextBox 控件实现灵活的过滤。
引言
您是否曾希望对 TextBox
控件的用户输入进行过滤?Code Project 上的其他解决方案是否过于狭隘,无法满足您的要求?您是否只是想更好地理解通用过滤?如果是,那么本文适合您。
本文描述了一个基类 FilterTextBox
,它可用于为 TextBox
控件实现灵活的过滤。
该类公开了一个新事件 TextChanging
,该事件在 Text
属性即将更改但尚未实际更改时触发。事件参数包含一个 AfterText
属性,用于预览拟议的更改。它们还包含一个 Cancel
属性,可以修改该属性以取消更改。
背景
“过滤”是什么意思?如果您想要一个 TextBox
控件,它将用户输入限制为仅数字,该怎么办?您将如何实现这一点?一种解决方案是使用 Validating
事件。不幸的是,此事件直到焦点离开控件后才触发。因此,用户至少会暂时看到无效输入。
如果能首先防止这些字符被看到,那不是很好吗?这就是通过过滤解决的问题。
事实上,如果您的过滤需求像刚才描述的那样简单,您可能应该使用 .NET 2.0 中引入的 MaskedTextBox
控件。
为什么要在这里提供另一种解决方案?这是一个公平的问题。就我而言,我还没有 .NET 2.0,我的过滤需求更复杂,而且我只是想了解事物是如何运作的。
我提供这个类,以防其他人有类似的需求。此外,我认为 TextChanging
事件可能对其他目的也有用。
使用代码
FilterTextBox
控件继承自标准 .NET TextBox
控件。它通过添加以下成员扩展了此控件的功能...
名称 | 类型 | 描述 |
TextChanging |
事件 |
在 Text 属性正在更改但尚未更改之前首次触发事件。 |
OnTextChanging() |
void |
在 Text 属性正在更改但尚未更改之前调用。 |
TextChangingWarn() |
void |
事件被取消时调用。如果未被覆盖,它会发出嘟嘟声。 |
CaretPosition |
int |
文本中插入符位置的索引。 |
FilterTextBox
控件最常见的用途可能是作为其他控件的基类。在这种情况下,最简单的使用方法是覆盖 OnTextChanging
方法。以下示例来自随附的 NumericTextBox
控件,演示了这种用法。在此示例中,会扫描新插入的文本以查找非数字字符。如果找到任何非数字字符,则将事件参数的 Cancel
属性设置为 true
。将 Cancel
设置为此值会阻止插入 Text
。
protected override void OnTextChanging (
TextChangingEventArgs e )
{
// If not cancelling and not deleting...
if (!e.Cancel && !e.IsDelete)
{
// Get text we need to validate
string text;
if (e.IsAssign)
text = e.AfterText;
else
text = e.InsertedText;
// Loop to validate text...
foreach(char charValue in text)
{
// If character is not a number...
if ( !Char.IsDigit(charValue) )
{
// Cancel the event
e.Cancel = true;
break;
} // If character is not a number...
} // Loop to validate text...
} // If not cancelling and not deleting...
// Notify other subscribers
base.OnTextChanging(e);
}
或者,也可以简单地订阅 TextChanging
事件。此方法的一个示例通过 FormMain
中的 alphabeticTextBox_TextChanging
方法提供。由于代码与上一个示例几乎相同,因此此处不显示。
在这些示例中的每一个中,都使用 TextChangingEventArgs
类来传达有关 TextChanging
事件的信息。它包含以下成员...
名称 | 类型 | 描述 |
取消 |
bool |
如果设置为 true,则将取消对 Text 属性的建议更改。 |
IsAssign |
bool | 如果为 true,则该事件与对 Text 属性的赋值相关联。 |
IsDelete | bool | 如果为 true,则该事件与字符删除相关联。 |
IsInsert | bool | 如果为 true,则该事件与字符插入相关联。 |
AfterText | 字符串 | 如果事件未取消,则 Text 属性的建议值。 |
BeforeText | 字符串 | 事件发生前 Text 属性的原始值。 |
InsertText | 字符串 | 如果 IsInsert 为 true,则包含正在插入的文本;否则,它包含 null 值。 |
类型 | TextChangingType | 导致 TextChanging 事件的操作类型。 |
BeforeRemoveStart | int | 原始文本中第一个被移除或替换的字符的索引。如果 IsInsert 为 true,它还指定原始文本中将插入字符的索引。 |
BeforeRemoveLength | int | 原始文本中正在移除或替换的字符数。 |
TextChangingType
只是导致 TextChanging
事件的所有操作的枚举。它们分为三类:赋值(参见 IsAssign
)、删除(参见 IsDelete
)和插入(参见 IsInsert
)。唯一的赋值类型是 Assign
。删除类型是:Backspace
、Clear
和 Cut
。插入类型是:KeyPress
和 Paste
。
实现
实现 FilterTextBox
的主要挑战是识别 TextBox
控件所有文本更改的来源。一旦识别出每个来源,就需要找到一种机制来拦截每个更改并取消它。
为此,我为我能找到的每个更改来源创建了一个表格。它们分为四类:TextBox
的上下文菜单、键盘输入、TextBox
控件的方法和 TextBox
控件的属性。
键盘输入是最明显的更改来源,因为这是控件旨在过滤的内容。所有非控制字符都通过覆盖 OnKeyPress
方法来拦截。每次按键都会触发一个类型为 TextChangingType.KeyPress
的 TextChanging
事件。如果事件被其中一个订阅者取消,则通过将 KeyPressEventArgs.Handled
设置为 true
来丢弃按键。
退格键和删除键也以类似的方式被拦截和取消。对于 Clear、Cut 和 Paste 等操作;覆盖 WndProc
方法以拦截相应的 Windows 消息似乎是最经济的解决方案。虽然不是纯 .NET,但它是我能找到的唯一能够透明地捕获上下文菜单操作的实用方法。
除了非控制键击之外的所有更改来源都在下表中详细说明...
类别 | 名称 | 拦截 | TextChangingType |
上下文菜单 | 删除 | FilterTextBox.WndProc() | Clear |
上下文菜单 | 剪切 | FilterTextBox.WndProc() | 剪切 |
上下文菜单 | 粘贴 | FilterTextBox.WndProc() | 粘贴 |
键盘输入 | 删除 | FilterTextBox.OnKeyDown() | Clear |
键盘输入 | Shift+Delete | FilterTextBox.WndProc() | 剪切 |
键盘输入 | Control+X | FilterTextBox.WndProc() | 剪切 |
键盘输入 | Shift+Insert | FilterTextBox.WndProc() | 粘贴 |
键盘输入 | Control+V | FilterTextBox.WndProc() | 粘贴 |
键盘输入 | 退格键 | FilterTextBox.OnKeyPress() | 退格键 |
方法 | TextBox.AppendText() | 不适用 | 不适用 |
方法 | TextBox.Clear() | FilterTextBox.Text | 赋值 |
方法 | TextBox.Cut() | FilterTextBox.WndProc() | 剪切 |
方法 | TextBox.Paste() | FilterTextBox.WndProc() | 粘贴 |
方法 | TextBox.ResetText() | FilterTextBox.Text | 赋值 |
属性 | TextBox.Text | FilterTextBox.Text | 赋值 |
遗憾的是,我无法找到一种方法来拦截和取消 TextBox.AppendText()
方法的更改。它无法被覆盖,并且不会将值赋给 Text
属性来更改其值。虽然这很不幸,但它不太可能影响大多数应用程序。
结论
鉴于关于这个主题的帖子很多,我曾犹豫是否要发布这篇文章。然而,我快速搜索到的解决方案中,没有一个致力于成为 TextBox 过滤的通用基类。相反,每个解决方案似乎都狭隘地针对解决特定的过滤需求(例如,一个数字 TextBox
)。
参考文献
修订历史
03-17-2007