I've noticed many applications that expect you to do a lot of text editing will provide non-default behavior for double clicking text in that the application highlights text that it believes you're most likely trying to interact with.
As a quick example, this sentence behaves differently in different applications:
This is a "sample" sentence
If I type that in Notepad and double click the word 'sample' (ideally middle of the word, say, between the 'm' and 'p' of sample) then notepad highlights from the first quote to the space after the second quote inclusive. If that sentence is in a comment in Visual Studio and I double click in the same location, it highlights from the 's' to the 'e' of sample without highlighting the quotes.
How can I customize these highlighting behaviors in my own application? Is it different from winforms to WPF? I suppose I could hack my way to make it work on a double click event, but is there a more elegant/deliberate solution meant exclusively for this?
Yes, using the DoubleClick event to do as you want is kludgy as it appears it's doing the selection twice which is slower, looks worse, and could trigger unwanted events/code.
So the code below should do the trick for Winforms at least. Create a new class, and extend the TextBox (or RichTextBox) in the usual manner (using the newly created control which should magically appear in the designer). I've made a simple routine where you can specify the delimiter to use. With a little more work, it should be easy to account for a range of a characters instead of just a single one, or even create other more advanced ways of selecting.
If you're using a TextBox instead of a RichTextBox, simply remove the "Rich" bit that appears twice in the class definition.
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);
}
}
The improved answer from DarkPh03n1X was almost working for me, however it has a nasty bug: if a delimiter character could not be found, Text.IndexOf(c, start)
will return -1
which will set right
to -1
and then if (right == -1) right = Text.Length
triggers.
So now we have selected until the end of the text, even though the expected selection should be shorter. The start is handled correctly I think.
I have removed if (right == -1) right = Text.Length
but added && pos != -1
. Here is the fixed version:
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);
}
}
To verify the behavour, here is the sample text I was using:
12.34.56.78 (ab1-2-3-4-5.test-1.example.com)
Jersey City
New Jersey
US, United States
ASN: Example.com/12345
I have added a few other delimiter, feel free to choose what you need.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With