防止选择 TextBox 中的文本

Prevent selecting text in a TextBox

已经有人问过类似的问题(例如,here),但是我还没有找到针对我的具体情况的答案。我正在构建一个基于 DevExpress 控件的自定义控件,该控件又基于标准 TextBox 并且我有一个闪烁的问题,这似乎是由于尝试更新选择的基本 TextBox 组件造成的。

无需解释我的自定义控件的所有细节,要重现该问题,您只需将 TextBox 放在 Form 中,然后使用此代码:

public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();
        textBox1.MouseMove += TextBox1_MouseMove;
    }

    private void TextBox1_MouseMove(object sender, MouseEventArgs e) {
        (sender as TextBox).Text = DateTime.Now.Ticks.ToString();
    }
}

如果启动它,单击 TextBox,然后将光标向右移动,您会注意到闪烁问题(参见视频 here)。对于我的自定义控件,我需要避免这种闪烁。我必须使用 TextBox(所以没有 RichTextBox)。有什么想法吗?

根据你想做什么,有几种解决方案:

如果你想阻止 selection 它将是:

        private void TextBox1_MouseMove(object sender, MouseEventArgs e)
    {
        (sender as TextBox).Text = DateTime.Now.Ticks.ToString();
        (sender as TextBox).SelectionLength = 0;
    }

或select全部:

        private void TextBox1_MouseMove(object sender, MouseEventArgs e)
    {
        (sender as TextBox).Text = DateTime.Now.Ticks.ToString();
        (sender as TextBox).SelectAll();
    }

除此之外,您还可以指定 selecting 的条件,例如:

        private void TextBox1_MouseMove(object sender, MouseEventArgs e)
    {
        (sender as TextBox).Text = DateTime.Now.Ticks.ToString();
        if (MouseButtons == MouseButtons.Left) (sender as TextBox).SelectAll();
        else (sender as TextBox).SelectionLength = 0;
    }

但是只要你想 select 文本你总是会得到一些闪烁,因为一个普通的文本框不可能使用像 BeginEdit 和 EndEdit 这样的东西,所以它会先改变文本然后然后select它。

看着视频,您的文本框似乎在不必要地调用 WM_ERASEBKGND。为了解决这个问题,您可以子class 文本框class 并拦截这些消息。下面是应该可以解决问题的示例代码(未经测试) 免责声明:我已将此技术用于其他 WinForm 控件,这些控件具有视频中显示的闪烁类型,但不是 TextBox。如果它对你有用,请告诉我。祝你好运!

// textbox no flicker
public partial class TexttBoxNF : TextBox
{
    public TexttBoxNF()
    {
    }

    public TexttBoxNF(IContainer container)
    {
        container.Add(this);

        InitializeComponent();

        //Activate double buffering
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

        //Enable the OnNotifyMessage event so we get a chance to filter out 
        // Windows messages before they get to the form's WndProc
        this.SetStyle(ControlStyles.EnableNotifyMessage, true);
    }

    //
    protected override void OnNotifyMessage(Message m)
    {
        //Filter out the WM_ERASEBKGND message
        if (m.Msg != 0x14)
        {
            base.OnNotifyMessage(m);
        }
    }
}

Reza Aghaei 同时通过覆盖 WndProc 和拦截 WM_SETFOCUS 消息提供了解决方案。参见 here