C# 防止在文本框上输入特殊字符(解决方案中已有数千个文本框)

C# 防止在文本框上输入特殊字符(解决方案中已有数千个文本框),c#,winforms,textbox,special-characters,C#,Winforms,Textbox,Special Characters,我们有一个用c#(windows窗体)编写的高级软件。在它们的文本框中,我们有1000个或更多文本框。我需要验证所有这些文本框上的用户输入,以停止输入特殊字符和任何脚本。文本框是硬编码的 例如: 我可以在每个按键上使用下面的代码来检查用户是否输入了允许的字符 private void textBox1_KeyPress(object sender, KeyPressEventArgs e) { var regex = new Regex(@"[^a-zA-Z0-9\s]&quo

我们有一个用c#(windows窗体)编写的高级软件。在它们的文本框中,我们有1000个或更多文本框。我需要验证所有这些文本框上的用户输入,以停止输入特殊字符和任何脚本。文本框是硬编码的

例如: 我可以在每个按键上使用下面的代码来检查用户是否输入了允许的字符

private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
    var regex = new Regex(@"[^a-zA-Z0-9\s]");
    if (regex.IsMatch(e.KeyChar.ToString()))
    {
        e.Handled = true;
    }
}
但是,我们必须在每个文本框按键事件上实现这一点(如果没有其他解决方案,这是最后一件要做的事情)。有没有办法从一个地方处理这个问题,并影响每个文本框(在某些地方,文本框也有自己的按键事件)。我需要的是一个通用的方法,它将在任何文本框的每个按键事件上触发

解决方案:创建一个从TextBox(或TextBoxBase)派生的自定义控件,该控件包含我的验证所需的所有逻辑,因此所有操作都在一个位置完成。 但我仍然必须再次更改所有现有的文本框,即我的新文本框。 是否有任何方法可以更改当前事件处理程序的行为


注意:我需要的是覆盖文本框的当前按键事件并运行我的验证代码,如果按键事件中有任何明确提到的代码,还需要运行。

如果要将
按键事件添加到所有
文本框
中,可以循环并添加相同的代码
EventHandler
用于所有事件

要做到这一点,首先我们需要创建一个循环遍历所有文本框的函数

GetChildControls函数:

公共静态IEnumerable GetChildControls(此控件)
其中TControl:Control
{
var children=(control.Controls!=null)?
control.Controls.OfType():Enumerable.Empty();
返回children.SelectMany(c=>GetChildControls(c)).Concat(children);
}
我们现在可以在
InitializeComponent()之后使用该函数
Txt\u KeyDown()
EventHandler分配给所有文本框

调用函数:

公共示例(){
初始化组件();
var alltextboxs=this.GetChildControls();
foreach(所有文本框中的文本框tb)
{
tb.KeyDown+=Txt\u KeyDown;
}
}
私有void Txt_KeyDown(对象发送方,System.Windows.Input.KeyEventArgs e){
//你的代码在这里
}
“有没有办法从一个地方处理这件事,并影响到所有人?” “每个文本框”

有几种方法。但是你似乎不想编辑文本框本身,所以我知道只有一种可靠的方法;连接全局键盘挂钩。代码如下:

class GlobalKeyboardHook
        {
            #region DLL Imports
            [DllImport("user32.dll")]
            static extern IntPtr SetWindowsHookEx(int hookEventId, keyboardProc callback, IntPtr handleInstance, uint threadId);

            [DllImport("user32.dll")]
            static extern bool UnhookWindowsHookEx(IntPtr handleInstance);

            [DllImport("user32.dll")]
            static extern int CallNextHookEx(IntPtr ignoredParameter, int hookCode, int wParam, ref KeyboardHookStruct lParam);

            [DllImport("kernel32.dll")]
            static extern IntPtr LoadLibrary(string libFileName);

            [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern IntPtr GetModuleHandle(string lpModuleName);
            #endregion DLL Imports

            #region Class Declarations
            private delegate int keyboardProc(int code, int wParam, ref KeyboardHookStruct lParam);
            private keyboardProc kbdProc;

            public struct KeyboardHookStruct
            {
                public int vkCode;
                public int scanCode;
                public int flags;
                public int time;
                public int extraInfo;
            }

            private static class KeyboardMessages
            {
                public const int WH_KEYBOARD_LL = 13;
                public const int WM_KEYDOWN = 0x100;
                public const int WM_KEYUP = 0x101;
                public const int WM_SYSKEYDOWN = 0x104;
                public const int WM_SYSKEYUP = 0x105;
            }
            
            IntPtr HookPointer = IntPtr.Zero;
            IntPtr ModuleInstance = IntPtr.Zero;

            public event KeyEventHandler KeyDown;
            public event KeyEventHandler KeyUp;

            #endregion Class Declarations

            #region Class Functions
            public GlobalKeyboardHook() {
                EnableHook(true, null);
            }

            public GlobalKeyboardHook(Process P) {
                EnableHook(true, P);
            }

            ~GlobalKeyboardHook() {
                EnableHook(false, null);
            }

            public void EnableHook(bool Enabled)
            {
                EnableHook(Enabled, null);
            }

            public void EnableHook(bool Enabled, Process P) {
                if (Enabled)
                {
                    HookPointer = SetWindowsHookEx(KeyboardMessages.WH_KEYBOARD_LL, kbdProc = HookCallback, ModuleInstance = P == null ? LoadLibrary("User32") : GetModuleHandle(P.MainModule.ModuleName), 0);
                }
                else
                {
                    UnhookWindowsHookEx(HookPointer);
                    HookPointer = IntPtr.Zero;
                    ModuleInstance = IntPtr.Zero;
                    kbdProc = null;
                }  
            }

            public int HookCallback(int code, int wParam, ref KeyboardHookStruct lParam) {
                if (code >= 0) {    
                    KeyEventArgs key = new KeyEventArgs((Keys)lParam.vkCode);
                    if ((wParam == KeyboardMessages.WM_KEYDOWN || wParam == KeyboardMessages.WM_SYSKEYDOWN) && (KeyDown != null)) {
                        KeyDown(this, key) ;
                    } else if ((wParam == KeyboardMessages.WM_KEYUP || wParam == KeyboardMessages.WM_SYSKEYUP) && (KeyUp != null)) {
                        KeyUp(this, key);
                    }
                    if (key.Handled)
                        return 1;
                }
                return CallNextHookEx(HookPointer, code, wParam, ref lParam);
            }
            #endregion Class Functions
        }
要激活,我们添加以下内容:

GlobalKeyboardHook ghk = new GlobalKeyboardHook(Process.GetCurrentProcess());
Type tbType = typeof(TextBox);
ghk.KeyDown += new KeyEventHandler(() => {
    if (typeof(this.ActiveControl) == tbType)
        RunValidation(this.ActiveControl.Text);
});
一旦有了样板挂钩,添加验证就变得非常简单了。“无循环”意味着您不会浪费处理器时间来迭代上千个文本框


请记住,这将应用于当前进程中TextBox类型的所有控件。如果您添加了一个自定义TextBox控件,或者不想检查所有这些控件,那么应该在调用RunValidation()之前考虑这些问题.

您是动态生成文本框还是硬编码?@MathewHD文本框是硬编码的?您为什么不构建一个从文本框派生的自定义控件,该控件包含验证所需的所有逻辑,因此所有操作都在一个位置完成?不需要事件处理程序,所有验证代码都在一个包中…@Jimi谢谢Jimi,但我仍然需要再次将所有现有的文本框更改为我的新文本框。是否有任何方法可以更改当前事件处理程序的行为?当然可以:
CTRL+H
,并将所有
新系统.Windows.Forms.TextBox()
事件替换为,例如,
new MySpecialTextBox()
(无论您为自定义类对象指定了什么名称)。-当然,在一个虚拟项目中做一个测试来熟悉它——你确定这个伪递归方法吗?看起来您正在其
控件
集合中搜索类型为
TControl
的子控件。因此,您将只返回此
的直接
t控件
子项。