双击文本区域或文本框时指定突出显示行为?

时间:2011-06-28 14:31:07

标签: c# text highlighting

我注意到许多希望您进行大量文本编辑的应用程序会为双击文本提供非默认行为,因为应用程序会突出显示它认为您最有可能尝试与之交互的文本。

作为一个简单的例子,这句话在不同的应用程序中表现不同:

  

这是一个“样本”句子

如果我在记事本中键入并双击“样本”一词(理想情况下是单词的中间位置,例如,样本的“m”和“p”之间),那么记事本会在第一个引号后突出显示第二次报价包含。如果该句子在Visual Studio中的注释中,并且我在同一位置双击,它会从样本的's'突出显示为'e'而不突出显示引号。

如何在自己的应用程序中自定义这些突出显示行为?是不同于winform到WPF?我想我可以破解我的方式使它在双击事件上工作,但是有一个更优雅/深思熟虑的解决方案专门用于此吗?

4 个答案:

答案 0 :(得分:3)

是的,使用DoubleClick事件按照您的意愿执行操作非常糟糕,因为它看起来正在进行两次选择,这种情况较慢,看起来更糟,并且可能会触发不需要的事件/代码。

所以下面的代码至少应该为Winforms做诀窍。创建一个新类,并以通常的方式扩展TextBox(或RichTextBox)(使用新创建的控件,它应该神奇地出现在设计器中)。我做了一个简单的例程,你可以指定要使用的分隔符。通过更多工作,可以轻松地考虑一系列角色而不仅仅是一个角色,甚至可以创建其他更高级的选择方式。

如果您使用的是TextBox而不是RichTextBox,只需删除在类定义中出现两次的“Rich”位。

class RichTextBoxX : RichTextBox
{
    char delimiter = ',';   // Specify what character to use for start and end of selection

    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        if (m.Msg==0x0203) // WM_LBUTTONDBLCLK
        {
            // Perfect situation for off-by-one bugs! Checked thoroughly for at least 10 mins, so should be okay now:
            int start = this.SelectionStart;
            if (start < 1) start = 1;
            int left = this.Text.LastIndexOf(delimiter, start - 1);
            int right = this.Text.IndexOf(delimiter, start);
            if (right == -1) right = Text.Length;
            this.SelectionStart = left + 1;
            this.SelectionLength = right - left - 1;
            return;             
        }

        base.WndProc(ref m);
    }
}

答案 1 :(得分:1)

来自DarkPh03n1X的改进答案几乎对我有用,但它有一个令人讨厌的错误:如果找不到分隔符Text.IndexOf(c, start)将返回{{ 1}}将-1设置为right然后设置-1触发。

所以现在我们已经选择了直到文本结尾,即使预期的选择应该更短。我认为开始是正确处理的。

我已移除if (right == -1) right = Text.Length但已添加if (right == -1) right = Text.Length。这是固定版本:

&& pos != -1

要验证行为,请参阅我正在使用的示例文本:

class RichTextBoxX : RichTextBox
{
    // implement selection to work with "whole words" on double-click 
    // and without selecting the leading/trailing spaces/blanks/line breaks
    private char[] delimiterList = new[] { '\n', ',', ' ', '(', ')', '_', '/' };

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x0203) // WM_LBUTTONDBLCLK
        {
            int start = SelectionStart;
            if (start < 1) start = 1;

            int left = -1;
            int right = Text.Length;
            int pos;

            foreach (char c in delimiterList)
            {
                pos = Text.LastIndexOf(c, start - 1);
                if (pos > left) left = pos;

                pos = Text.IndexOf(c, start);
                if (pos < right && pos != -1) right = pos;
            }

            SelectionStart = left + 1;
            SelectionLength = right - left - 1;
            return;
        }

        base.WndProc(ref m);
    }
}

我添加了一些其他分隔符,随时可以选择您需要的内容。

答案 2 :(得分:1)

我使用等于\w的正则表达式[a-zA-Z0-9_]来代替TextBox选择

private void TextBox1_MouseDoubleClick(object sender, MouseEventArgs e)
{
    string text = TextBox1.SelectedText;
    var strA = Regex.Match(text, @"\w+");
    int indexA = TextBox1.SelectionStart + text.IndexOf(strA.Value);
    TextBox1.Select(indexA, strA.Value.Length);
}

原始结果:

这是"sample"

使用上述方法

这是一个“ sample”句子

答案 3 :(得分:0)

添加到DanW的工作我添加了多个分隔符,这似乎很好用。

class RichTextBoxX : RichTextBox
{
    private char[] delimiterList = new[] { ',', ' '};

    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        if (m.Msg == 0x0203) // WM_LBUTTONDBLCLK
        {
            int start = this.SelectionStart;
            if (start < 1) start = 1;

            int left = -1;
            int right = Text.Length;

            foreach (char c in delimiterList)
            {
                if (this.Text.LastIndexOf(c, start - 1) > left)
                {
                    left = this.Text.LastIndexOf(c, start - 1);
                }

                if (this.Text.IndexOf(c, start) < right)
                {
                    right = this.Text.IndexOf(c, start);
                    if (right == -1) right = Text.Length;
                }
            }

            this.SelectionStart = left + 1;
            this.SelectionLength = right - left - 1;
            return;
        }

        base.WndProc(ref m);
    }
}

还有一件事:实现将上面的代码粘贴到您要使用它的表单的“代码”中,现在使用“表单设计器”将RichTextBox拖放到表单上,现在转到表单的在我的案例form1.desigener.cs中的设计器类,并找到实现字符串,例如:

this.richTextBox1 = new System.Windows.Forms.RichTextBox();

并将其替换为

this.richTextBox1 = new project.form1.RichTextBoxX();

在此之后,该控件将像普通的RichTextBox实现一样工作,具有额外的覆盖功能