C# 我们可以在不创建自定义控件的情况下截取多个文本框的按键事件吗?

C# 我们可以在不创建自定义控件的情况下截取多个文本框的按键事件吗?,c#,winforms,textbox,C#,Winforms,Textbox,是否有任何方法可以覆盖文本框的原始按键事件的行为而不添加UserControl 我的问题是: 我有一个大项目,我有1000多个文本框。它们以不同的形式存在。我必须验证用户输入,以防止输入特殊字符 我知道防止这种情况发生的代码,但随后我必须将该代码放入每个TextBox的每个KeyPress事件处理程序中,或者我必须创建一个从TextBox类派生的自定义控件,覆盖OnKeypress,如果表单上的按键事件中明确声明了代码,则调用基类,并在任何地方替换自定义控件 是否有其他方法可以截取文本框的按键事

是否有任何方法可以覆盖文本框的原始
按键
事件的行为而不添加UserControl

我的问题是:
我有一个大项目,我有1000多个文本框。它们以不同的形式存在。我必须验证用户输入,以防止输入特殊字符

我知道防止这种情况发生的代码,但随后我必须将该代码放入每个TextBox的每个KeyPress事件处理程序中,或者我必须创建一个从TextBox类派生的自定义控件,覆盖OnKeypress,如果表单上的按键事件中明确声明了代码,则调用基类,并在任何地方替换自定义控件

是否有其他方法可以截取文本框的按键事件并仅在一个位置进行此更改?

以下是几个示例:

  • 一个简单的共享类,允许使用预定义的事件处理程序订阅事件
  • 一个自定义控件,可以根据特定允许的模式筛选按键。这里,我使用的是您之前发布的与
    按键相关的事件过滤器。此筛选器可能需要更多注意。
    例如,我添加了一个公共属性,
    public bool NumbersOnly
    ,可用于使自定义TextBox控件仅接受数字。激活时,它会清除任何非数字字符中的文本。当按下不允许的键时,
    ErrorProvider
    会给出反馈
  • 示例集中式事件处理程序

    public partial class SomeForm : Form
    {
        public SomeForm()
        {
            InitializeComponent();
    
            // Get all TextBoxes in the current Form and subscribe to some events 
            foreach (var textBoxes in this.FindAll<TextBox>()) {
                textBoxes.TextChanged += MyEventsHandler.TextBoxTextChanged_Handler;
                textBoxes.KeyPress += MyEventsHandler.TextBoxKeyPress_Handler;
        }
    
        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            foreach (var textBoxes in this.FindAll<TextBox>()) {
                textBoxes.TextChanged -= MyEventsHandler.TextBoxTextChanged_Handler;
                textBoxes.KeyPress -= MyEventsHandler.TextBoxKeyPress_Handler;
            }
            base.OnFormClosing(e);
        }
    }
    
    扩展方法:

    public static class ControlExtensions
    {
        public static IEnumerable<T> FindAll<T>(this Control control) where T: Control
        {
            foreach (Control ctl in control.Controls) {
                foreach (Control child in ctl.FindAll<T>()) {
                    if (child is T ch) yield return ch;
                }
                if (ctl is T c) yield return c;
            }
        }
    }
    

    处理窗体的按键事件,它将在到达控件之前“拦截”它。您可以从传递的事件参数中检查哪个控件调用了它。

    这是否回答了您的问题@不幸的是,你到底想实现什么?如果我理解正确,您只想让所有文本框使用相同的按键事件,我已经在您的原始问题中添加了一个关于如何使用相同按键事件的答案。@MathewHD截取已实现文本框的当前按键事件。如果这些按键事件中有任何代码,请运行,然后最后运行我的验证代码。不添加任何用户控件。确定。您可以将一个类对象添加到添加事件处理程序的项目中,并使控件仅使用此处理程序订阅事件。我建议创建一个自定义控件(不是UserControl,不同的东西)(顺便说一句,在自定义控件中,您不重写事件,而是重写引发事件的方法-
    OnKeyPress
    ,在这种情况下-当然,调用
    base.OnKeyPress(e)
    ,以允许事件的正常使用)。然后您就有了一个包含所需逻辑的可重用控件,如果需要,您可以使用新功能对其进行扩展。不需要更改项目中的任何其他内容。
    public static class ControlExtensions
    {
        public static IEnumerable<T> FindAll<T>(this Control control) where T: Control
        {
            foreach (Control ctl in control.Controls) {
                foreach (Control child in ctl.FindAll<T>()) {
                    if (child is T ch) yield return ch;
                }
                if (ctl is T c) yield return c;
            }
        }
    }
    
    using System;
    using System.ComponentModel;
    using System.Security.Permissions;
    using System.Text.RegularExpressions;
    using System.Windows.Forms;
    
    [ToolboxItem(true)]
    [DesignerCategory("Code")]
    public class TextBoxEx : TextBox
    {
        private const int ES_NUMBER = 0x2000;
        private bool m_NumbersOnly = false;
        private Regex regex = new Regex(@"[^a-zA-Z0-9\s\b]", RegexOptions.Compiled);
    
        public TextBoxEx() { }
    
        public bool NumbersOnly {
            get => m_NumbersOnly;
            set {
                if (m_NumbersOnly != value) {
                    m_NumbersOnly = value;
                    this.Text = Regex.Replace(this.Text, @"\D", "");
                    this.RecreateHandle();
                }
            }
        }
    
        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            if (regex.IsMatch(e.KeyChar.ToString())) {
                e.Handled = true;
            }
            base.OnKeyPress(e);
        }
    
        protected override CreateParams CreateParams
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
            get {
                CreateParams cp = base.CreateParams;
                if (m_NumbersOnly) {
                    cp.Style |= ES_NUMBER;
                }
                else {
                    cp.Style &= ~ES_NUMBER;
                }
                return cp;
            }
        }
    }