65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (6投票s)

2007 年 3 月 20 日

5分钟阅读

viewsIcon

45318

downloadIcon

699

本文描述了一个基类 FilterTextBox,它可用于为 TextBox 控件实现灵活的过滤。

Screenshot - FilterTextBox.png

引言

您是否曾希望对 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 属性的赋值相关联。
IsDeletebool如果为 true,则该事件与字符删除相关联。
IsInsertbool如果为 true,则该事件与字符插入相关联。
AfterText字符串如果事件未取消,则 Text 属性的建议值。
BeforeText字符串事件发生前 Text 属性的原始值。
InsertText字符串如果 IsInsert 为 true,则包含正在插入的文本;否则,它包含 null 值。
类型TextChangingType导致 TextChanging 事件的操作类型。
BeforeRemoveStartint原始文本中第一个被移除或替换的字符的索引。如果 IsInsert 为 true,它还指定原始文本中将插入字符的索引。
BeforeRemoveLengthint原始文本中正在移除或替换的字符数。

TextChangingType 只是导致 TextChanging 事件的所有操作的枚举。它们分为三类:赋值(参见 IsAssign)、删除(参见 IsDelete)和插入(参见 IsInsert)。唯一的赋值类型是 Assign。删除类型是:BackspaceClearCut。插入类型是:KeyPressPaste

实现

实现 FilterTextBox 的主要挑战是识别 TextBox 控件所有文本更改的来源。一旦识别出每个来源,就需要找到一种机制来拦截每个更改并取消它。

为此,我为我能找到的每个更改来源创建了一个表格。它们分为四类:TextBox 的上下文菜单、键盘输入、TextBox 控件的方法和 TextBox 控件的属性。

键盘输入是最明显的更改来源,因为这是控件旨在过滤的内容。所有非控制字符都通过覆盖 OnKeyPress 方法来拦截。每次按键都会触发一个类型为 TextChangingType.KeyPressTextChanging 事件。如果事件被其中一个订阅者取消,则通过将 KeyPressEventArgs.Handled 设置为 true 来丢弃按键。

退格键和删除键也以类似的方式被拦截和取消。对于 Clear、Cut 和 Paste 等操作;覆盖 WndProc 方法以拦截相应的 Windows 消息似乎是最经济的解决方案。虽然不是纯 .NET,但它是我能找到的唯一能够透明地捕获上下文菜单操作的实用方法。

除了非控制键击之外的所有更改来源都在下表中详细说明...

类别名称拦截TextChangingType
上下文菜单删除FilterTextBox.WndProc()Clear
上下文菜单剪切FilterTextBox.WndProc()剪切
上下文菜单粘贴FilterTextBox.WndProc()粘贴
键盘输入删除FilterTextBox.OnKeyDown()Clear
键盘输入Shift+DeleteFilterTextBox.WndProc()剪切
键盘输入Control+XFilterTextBox.WndProc()剪切
键盘输入Shift+InsertFilterTextBox.WndProc()粘贴
键盘输入Control+VFilterTextBox.WndProc()粘贴
键盘输入退格键FilterTextBox.OnKeyPress()退格键
方法TextBox.AppendText()不适用不适用
方法TextBox.Clear()FilterTextBox.Text赋值
方法TextBox.Cut()FilterTextBox.WndProc()剪切
方法TextBox.Paste()FilterTextBox.WndProc()粘贴
方法TextBox.ResetText()FilterTextBox.Text赋值
属性TextBox.TextFilterTextBox.Text赋值

遗憾的是,我无法找到一种方法来拦截和取消 TextBox.AppendText() 方法的更改。它无法被覆盖,并且不会将值赋给 Text 属性来更改其值。虽然这很不幸,但它不太可能影响大多数应用程序。

结论

鉴于关于这个主题的帖子很多,我曾犹豫是否要发布这篇文章。然而,我快速搜索到的解决方案中,没有一个致力于成为 TextBox 过滤的通用基类。相反,每个解决方案似乎都狭隘地针对解决特定的过滤需求(例如,一个数字 TextBox)。

参考文献

  • TextBox 类 (MSDN), http://msdn2.microsoft.com/en-us/library/system.windows.forms.textbox.aspx

    修订历史

    03-17-2007

  • 原始文章。
  • © . All rights reserved.