【问题标题】:Prevent inserting special characters on Usercontrol (textbox) by Copy Paste通过复制粘贴防止在用户控件(文本框)上插入特殊字符
【发布时间】:2020-10-08 07:02:09
【问题描述】:

我必须验证用户控件(文本框)是否插入特殊字符。在按键事件中,我使用此代码来处理此问题。

OnKeyPress 覆盖:

protected override void OnKeyPress(KeyPressEventArgs e) {
    base.OnKeyPress(e);
    MethodToPrevent(e);
}

MethodToPrevent 函数:

private void MethodToPrevent(KeyPressEventArgs e) {
    var regex = new Regex(@"[^a-zA-Z0-9\s]");
    if (regex.IsMatch(e.KeyChar.ToString())) {
        e.Handled = true;
    }
}

现在一切正常。但是,如果用户复制粘贴带有特殊字符的字符串,这是行不通的。我该如何处理?

试过

protected override void OnTextChanged(EventArgs args)

但是在这里无法捕捉到 Sender 部分。

【问题讨论】:

  • 也许尝试使用另一个事件? TextChanged? Paste?
  • "但无法在此处捕获 Sender 部分。"如果您尝试使用OnTextChanged(),那么“发送者”就是您所在的类,因为这是一个 OVERRIDE 方法,您必须在派生类中?...

标签: c# winforms copy-paste


【解决方案1】:

实际上您的代码阻止了 ctrl,但它不阻止鼠标右键单击和粘贴。也许您可以阻止鼠标右键单击,或者您可以使用 TextChanged 事件。

private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
    base.OnKeyPress(e);
    MethodToPrevent(e);
}

private void MethodToPrevent(KeyPressEventArgs e)
{
    var regex = new Regex(@"[^a-zA-Z0-9\s]");
    if (regex.IsMatch(e.KeyChar.ToString()))
    {
        e.Handled = true;
    }
}

// If the user presses the wrong key, it is already blocked with the 
//MethodToPrevent() before the TextChanged().
//it is only prevent mouse right click and paste
private void textBox1_TextChanged(object sender, EventArgs e)
{
    var regex = new Regex(@"[^a-zA-Z0-9\s]");
    if (regex.IsMatch(textBox1.Text.ToString()))
    {
        textBox1.Text = "";
    }
}

【讨论】:

  • 那么,如果你得到一个不需要的字符,你会在它的 TextChanged 事件处理程序中清除控件的整个文本吗? Sinatr 在评论中发布了指向禁用 WM_PASTE 的答案的链接。它也可以用于不同的东西,例如,警告用户它的粘贴包含不允许的字符。
  • 我只是想指定可以使用 textchanged 事件。此代码的高级版本是在 textchanged 事件运行时查找并删除不需要的字符。
  • 您通常尽量不要在其 TextChanged 事件中更改控件的文本。或者,如果用户按下了错误的键,则清除整个文本(在 TextChanged 事件中)。不确定此代码的高级版本是什么意思。
  • 否,如果用户按错键,则在 TextChanged() 之前已被 MethodToPrevent() 阻止。
  • 这种操作的想法是防止事情发生,而不是在已经发生后尝试修补它。因此,您想要做的是,如果不允许以任何方式输入某些内容,则首先要防止 Text 发生更改。 + 您假设为 Regex 旨在拦截的每个字符引发 KeyPress 事件。此外,如前所述,原则上您应该尽量避免在 TextChanged 事件中更改控件的文本(是的,我知道,我已经说过了)。
【解决方案2】:

由于您显然使用的是自定义控件(派生文本框),一些建议来处理您的控件中的用户粘贴操作和过滤文本编辑(过滤器部分是您提供的,这个部门需要做更多的工作这防弹 - 不仅仅是与错误处理有关)。

此自定义控件为标准文本框添加了一些功能:

  1. 过滤由OnKeyPress 处理的字符,允许光标移动,删除退格(我已将\b 添加到过滤器正则表达式中,我认为它丢失了)。

  2. 以 3 种不同方式过滤 WM_PASTE 事件,使用链接到公共 UserPaste 属性的 PasteAction 枚举,该属性定义响应粘贴操作的控件行为(修改为必填):

    • Allow:用户可以在 TextBox 中粘贴任何内容
    • Partial:用户只能粘贴正则表达式过滤器允许的内容,其余内容被删除
    • Disallow:用户无法粘贴任何内容
  3. 在基类级别(无正则表达式)有一个仅允许数字的选项。这与ErrorProvider 类提供的反馈相结合。

为了允许部分粘贴功能,WndProc 覆盖拦截 WM_PASTE,使用 Clipboard.GetText() 方法(使用 TextDataFormat.UnicodeText)过滤从剪贴板读取的文本,然后发送向编辑控件发送EM_REPLACESEL 消息,以添加修改后的文本(对用户而言,它显示为实际的粘贴操作)。

base.WndProc() 在任何情况下都不会被调用,剪贴板也不会被触及。
→ 如果您要通知用户所采取的操作,请不要在 WndProc 方法覆盖中显示 MessageBox。

注意:这是我已经发布here 的自定义控件的修改版本(还有一些可能派上用场的其他方法),完全相同。 → 如果这两个问题确实相关,请告诉我。


using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using System.Windows.Forms;

[ToolboxItem(true)]
[DesignerCategory("Code")]
public class TextBoxEx : TextBox
{
    private bool m_NumbersOnly = false;
    private Regex regex = new Regex(@"[^a-zA-Z0-9\s\b]", RegexOptions.Compiled);

    public TextBoxEx() { }

    public enum PasteAction
    {
        Allow,
        Disallow,
        Partial
    }

    public PasteAction UserPaste { get; set; }

    public override string Text {
        get => base.Text;
        set {
            if (!base.Text.Equals(value)) {
                base.Text = regex.Replace(value, "");
            }
        }
    }

    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 |= NativeMethods.ES_NUMBER;
            }
            else {
                cp.Style &= ~NativeMethods.ES_NUMBER;
            }
            return cp;
        }
    }

    protected override void WndProc(ref Message m)
    {
        switch (m.Msg) {
            case NativeMethods.WM_PASTE:
                switch (UserPaste) {
                    case PasteAction.Disallow:
                        return;
                    case PasteAction.Partial:
                        string text = Clipboard.GetText(TextDataFormat.UnicodeText);
                        text = regex.Replace(text, "");
                        NativeMethods.SendMessage(this.Handle, NativeMethods.EM_REPLACESEL, 1, text);
                        return;
                    case PasteAction.Allow:
                        break;
                }
                break;
        }
        base.WndProc(ref m);

    }

    private class NativeMethods
    {
        internal const int WM_PASTE = 0x0302;
        internal const int ES_NUMBER = 0x2000;
        internal const int EM_REPLACESEL = 0xC2;

        [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        internal static extern int SendMessage(IntPtr hWnd, uint uMsg, int wParam, string lParam);
    }
}

【讨论】:

    猜你喜欢
    • 2019-07-09
    • 1970-01-01
    • 2016-01-06
    • 2013-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-12
    • 2019-08-09
    相关资源
    最近更新 更多