5

I created an event handler for the Textbox.Enter event, which selects a part of the text inside the textbox, like this:
TextBox1.Select(3,5);

The result looks like this:

When the Textbox is entered via the Keyboard via [Tab] or [Shift]-[Tab],
the part of the text that needs to be selected is selected well, just like in the screenshot above.

However if the textbox is entered not via the keyboard but via the mouse,
then nothing is selected:

It seems that what happens is this:

When we enter the textbox with the mouse,
the click indeed raises the Enter event, but the mouseclick also sets the location of the cursor, to the location the user clicked with the mouse, inside the textbox.
And this setting of the cursor happens right after the event handler was ran.

So this means, that the selection that the event handler performed (with the TextBox1.Select(3,5); line), is overridden by the mouse's location,
and that's why entering the textbox with the mouse, appears to not select anything.

My question:

How can I make the mouse indeed raise the Enter event, yet not change the cursor position inside the textbox?
So I will then be able to have my selection (that happens in code) remain and not be overridden..

Edit:
The purpose of this is to enable easy selection of the MM:SS part of the time, which is usually the part that is being edited (the HH or mmm parts are rarely changed).

spaceman
  • 1,061
  • 1
  • 11
  • 31
  • 1
    You are just getting a preview of what happens whenever the user clicks the textbox with the mouse. Your Select() call works just fine, it only lasts for a microsecond. It is not clear from the question if *all* mouse clicks should be disabled. – Hans Passant Jan 03 '16 at 13:15

2 Answers2

2

A bit strange request, but if you really want to do so, you can use a well known general method for scheduling an action to be executed later (after normal windows message/event processing) by using the Control.BeginInvoke method.

Something like this

void textBox_Enter(object sender, EventArgs e)
{
    BeginInvoke(new Action(() => textBox.Select(3, 5)));
}

Update: As per your comment, if you want to prevent the default mouse down behavior, you need to handle the WM_MOUSEACTIVATE message by creating and using your own TextBox subclass like this

class MyTextBox : TextBox
{
    protected override void WndProc(ref Message m)
    {
        const int WM_LBUTTONDOWN = 0x0201;
        const int WM_MOUSEACTIVATE = 0x0021;
        const int MA_ACTIVATEANDEAT = 2;
        const int MA_NOACTIVATEANDEAT = 4;

        if (m.Msg == WM_MOUSEACTIVATE && !Focused)
        {
            int mouseMsg = unchecked((int)((uint)(int)m.LParam >> 16)); // LOWORD(m.LParam)
            if (mouseMsg == WM_LBUTTONDOWN)
            {
                bool activated = Focus();
                m.Result = (IntPtr)(activated ? MA_ACTIVATEANDEAT : MA_NOACTIVATEANDEAT);
                return;
            }
        }
        base.WndProc(ref m);
    }
}
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • Thank you Ivan. I actually considered using a delay, but was wishing for more like a prevention way - a way to prevent the cursor being changed, instead of having it to happpen and then changing it.. Is it possible to achieve it via disabling the change of the cursor location? – spaceman Jan 03 '16 at 11:56
  • 1
    There is a solution, but it's much more complicated - requires subclassing the `TextBox` and handling the `WM_MOUSEACTIVATE` message. – Ivan Stoev Jan 03 '16 at 12:22
  • I understand. Thank you very much Ivan – spaceman Jan 03 '16 at 12:34
1

I would like to suggest another way:

In the beginning of the Control.Enter event handler, I put this:

while( (Control.MouseButtons&MouseButtons.Left)!=0 )
    Application.DoEvents();

This simply waits for the mouse Left button to be released..

Only when the mouse Left button is released, then we continue to the next line of code, which is

TextBox1.Select(3,5);

and it then works well - the selection happens, without being overridden.

spaceman
  • 1,061
  • 1
  • 11
  • 31