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

简单数字文本框

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.69/5 (27投票s)

2008年11月9日

CPOL

3分钟阅读

viewsIcon

138220

downloadIcon

5858

一个只接受数字的 WinForms 文本框。

概述

这是 System.Windows.Forms.TextBox 组件的一个简单扩展/限制。只有数字可以输入到控件中。粘贴也会被检查,如果文本包含其他字符,则会被取消。我在各个网站上找到了许多示例,但没有一个适合我的目的。它们要么允许或强制执行我不想要的东西(参见下面的“我没有做的事情”),要么没有完全处理所有标准的键盘和鼠标功能(参见下面的“这肯定很简单”),例如,允许 Home 键或 Shift+End 等。

语言

源代码使用 C#,.NET 2.0, VS2008。我包含了已编译的 DLL,因此 VB 用户可以使用此控件。

我没有做的事情

我没有添加任何范围或边界控制 - 这是一个文本框,而不是 int/double/decimal... 框。不支持数字分隔符、货币符号,甚至 - 符号。我的实现不需要它们。如果您想添加它们,应该不会太难。

这肯定很简单,你只需要...

我也是这么想的,直到开始编写代码两分钟后!实际上,我们一直在使用文本框做很多事情,但从未仔细考虑过。除了数字之外,我们还需要允许编辑键组合和导航/选择键和组合。粘贴可以通过键盘或鼠标操作完成,因此仅处理键盘事件是不够的。

代码

代码中有趣的部分在重写的 OnKeyDown 和私有的 CheckPasteValid 方法中。

OnKeyDown

我只是为数字键、编辑键和导航键构建了 bools,这样我可以测试每个组的一个值。 Ctrl+A 有时需要单独处理,所以我为此也创建了一个。

protected override void OnKeyDown(KeyEventArgs e)
{
    bool result = true;

    bool numericKeys = (
        ((e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9) ||
        (e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9))
        && e.Modifiers != Keys.Shift);

    bool ctrlA = e.KeyCode == Keys.A && e.Modifiers == Keys.Control;

    bool editKeys = (
        (e.KeyCode == Keys.Z && e.Modifiers == Keys.Control) ||
        (e.KeyCode == Keys.X && e.Modifiers == Keys.Control) ||
        (e.KeyCode == Keys.C && e.Modifiers == Keys.Control) ||
        (e.KeyCode == Keys.V && e.Modifiers == Keys.Control) ||
        e.KeyCode == Keys.Delete ||
        e.KeyCode == Keys.Back);

    bool navigationKeys = (
        e.KeyCode == Keys.Up ||
        e.KeyCode == Keys.Right ||
        e.KeyCode == Keys.Down ||
        e.KeyCode == Keys.Left ||
        e.KeyCode == Keys.Home ||
        e.KeyCode == Keys.End);

    if (!(numericKeys || editKeys || navigationKeys))
    {
        if (ctrlA)
        // Do select all as OS/Framework
        // does not always seem to implement this.
            SelectAll();
        result = false;
    }
    if (!result) // If not valid key then suppress and handle.
    {
        e.SuppressKeyPress = true;
        e.Handled = true;
        if (ctrlA) { } // Do Nothing!
        else
            OnKeyRejected(new KeyRejectedEventArgs(e.KeyCode));
    }
    else
        base.OnKeyDown(e);
}

CheckPasteValid

当收到粘贴消息时,它会在重写的 WndProc 中捕获,然后调用此方法。根据结果,如果必要,它会在不调用基类的 WndProc 的情况下返回,从而取消该消息。 CheckPasteValid 的代码如下所示。设置默认值后,我们尝试从剪贴板获取文本。如果出现错误或没有有效文本,则会设置相应的拒绝原因并返回。如果一切正常,我们然后从当前文本和剪贴板的文本构建一个字符串。最后一步是检查剪贴板的文本是否包含任何非数字字符,并设置所需的拒绝原因。

private PasteEventArgs CheckPasteValid()
{
    // Default values.
    PasteRejectReasons rejectReason = PasteRejectReasons.Accepted;
    string originalText = Text;
    string clipboardText = string.Empty;
    string textResult = string.Empty;

    try
    {
        clipboardText = Clipboard.GetText(TextDataFormat.Text);
        if (clipboardText.Length > 0) // Does clipboard contain text?
        {
            // Store text value as it will be post paste assuming it is valid.
            textResult = (
                Text.Remove(SelectionStart, 
                SelectionLength).Insert(SelectionStart, clipboardText));
            foreach (char c in clipboardText) // Check for any non digit characters.
            {
                if (!char.IsDigit(c))
                {
                    rejectReason = PasteRejectReasons.InvalidCharacter;
                    break;
                }
            }
        }
        else
            rejectReason = PasteRejectReasons.NoData;
    }
    catch
    {
        rejectReason = PasteRejectReasons.Unknown;
    }
    return new PasteEventArgs(originalText, clipboardText, textResult, rejectReason);
}

新内容

事件

  • KeyRejected - 当 KeyDown 事件被阻止时发生。
  • PasteRejected - 当粘贴尝试被禁止时发生。

属性

  • DefaultText - 没有值时使用的字符串(不能为 null 或空)。

嵌套类

有两个嵌套的事件参数类。

KeyRejectedEventArgs

每次阻止按下键时都会创建此实例。它只有一个属性

  • Key - 被拒绝的键 (System.Windows.Forms.Keys)。

PasteEventArgs

每次收到粘贴消息时都会创建此实例。它在内部使用,但其主要目的是作为 PasteRejected 事件中的事件参数。它有四个属性

  • OriginalText - 粘贴之前(如果被拒绝,仍然是)的文本。
  • ClipboardText - 尝试粘贴的文本。
  • TextResult - 粘贴的结果(或本来是)的文本。
  • RejectReason - 一个枚举 (PasteRejectReasons),指示被拒绝的原因(如果被拒绝),或者用于内部使用的 PasteRejectReasons.Accepted(如果粘贴 OK)。

历史

  • 2008 年 11 月 7 日:初始版本。
© . All rights reserved.