5

I'm using WinForms and on my Form I have a RichTextBox. When my form is out of focus but visible and I try to highlight/select text, it does not allow me to until the form or textbox itself has focus.

I've tried:

txtInput.MouseDown += (s, e) => { txtInput.Focus(); }

but to no avail and I can't seem to find anything online about this issue.

When testing with another program like Notepad, it does possess the desired behavior.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • I didn't understand this question at first. Here's the test: Open notepad. type in some random text. Focus on a different window with notepad in view. Hold down the mouse button while clicking in notepad, like you're going to highlight text. Try the same thing in a rich textbox. The text won't highlight. – oppassum Apr 21 '16 at 18:05
  • Set `HideSelection = false` – TaW Apr 21 '16 at 18:12
  • @TaW I also suggested that, but after reading the comment of oppassum, I realized that the problem probably is: `RichTextBox` selection is not working when the form doesn't have focus, while you can simply perform selection by mouse on notepad.exe for example even if it doesn't have focus. It got the focus and continue selection, but for `RichTextBox` only got the focus and for selection, you should perform another mouse down. – Reza Aghaei Apr 21 '16 at 18:21
  • @reza: Ah, indeed, I missed the point. – TaW Apr 21 '16 at 18:54

4 Answers4

3

MouseDown is too late.

This is a workaround for sure, but may be all you need:

private void txtInput_MouseMove(object sender, MouseEventArgs e)
{
    txtInput.Focus();
}

or of course:

txtInput.MouseMove += (s, e) => { txtInput.Focus(); }

As it is it may steal focus from other controls on your form when you move over the textbox. If this is a problem you could prevent it by checking if your program is active using one the of answers here..

Community
  • 1
  • 1
TaW
  • 53,122
  • 8
  • 69
  • 111
2

You can make the selection manually using MouseDown and MouseMove events. The answer is based on Taw's first idea:

int start = 0;
private void richTextBox1_MouseDown(object sender, MouseEventArgs e)
{
    start = richTextBox1.GetTrueIndexPositionFromPoint(e.Location);
    richTextBox1.SelectionStart = start;
}

private void richTextBox1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button.HasFlag(MouseButtons.Left))
    {
        var current = richTextBox1.GetTrueIndexPositionFromPoint(e.Location);
        richTextBox1.SelectionStart = Math.Min(current, start);
        richTextBox1.SelectionLength = Math.Abs(current - start);
    }
}

And here is the codes for GetTrueIndexPositionFromPoint method which has taken from Justin:

public static class RichTextBoxExtensions
{
    private const int EM_CHARFROMPOS = 0x00D7;
    public static int GetTrueIndexPositionFromPoint(this RichTextBox rtb, Point pt)
    {
        POINT wpt = new POINT(pt.X, pt.Y);
        int index = (int)SendMessage(new HandleRef(rtb, rtb.Handle), EM_CHARFROMPOS, 0, wpt);
        return index;
    }

    [DllImport("User32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, POINT lParam);
}
Community
  • 1
  • 1
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • Hm, sorry, but I can't say it does anything for me. Maybe I'm getting tired ;-) – TaW Apr 21 '16 at 22:04
2

This worked for me;

Extend RichTextBox and override WindowProc with this

protected override void WndProc(ref Message m) {
    const int WM_MOUSEACTIVATE = 0x21;

    if (m.Msg == WM_MOUSEACTIVATE) {
        // Take focus to enable click-through behavior for setting selection
        this.Focus();
    }

    // Let the base handle the event.
    base.WndProc(ref m);
}
micnil
  • 4,705
  • 2
  • 28
  • 39
1

This soulution didn't work for me since my child window had a TextBox that would lose focus when I would hover over the RichTextBox. After some trial and error, I've managed to find another solution:

    private const int WM_PARENTNOTIFY = 0x0210;

    private Form Form = new Form(); // Your Form here!
    private RichTextBox RTB = new RichTextBox(); // Your RichTextBox here!

    protected override void WndProc(ref Message m) 
    {
        if ((m.Msg == WM_PARENTNOTIFY) && (Form != null) && (Form.Visible) && (GetChildAtPoint(PointToClient(Cursor.Position)) == RTB))
        {
            RTB.Focus();
        }

        base.WndProc(ref m);
    }

The WM_PARENTNOTIFY message can be sent multiple times (including when the main Form is being initialized) so it is important to check that that your Form isn't null otherwise you'll receive an exception.

Doe
  • 11
  • 2