2

I have a ListBox on the left side of my form. The user has the option of "auto-hiding" it so that it disappears off to the left, and only reappears while the user moves their mouse onto it.

If the ListBox has few items in it, this feature works beautifully.

However as soon as I put enough items into the ListBox such that there is now a scrollbar, funny things start to happen. The MouseEnter code is only triggered when the user has moved their mouse into the ListBox past the scrollbar. This means that I must have more then the width of the scroll bar peeking or they will never be able to show it.

Additionally, the user is not able to scroll at all if the ListBox is not in focus. If they try to click the scrollbar to scroll, the ListBox disappears. If they click inside the ListBox to focus it (so that they can scroll with the mouse wheel), then they lose their selection.

Is there any way I can extend the bounds of MouseEnter and MouseLeave to include the scrollbar?

2
  • 1
    I presume you mean scrollbar throughout, not progress bar? Commented Jun 29, 2011 at 0:22
  • Thanks, you're right. I haven't had my coffee yet so my brain is running at about 30% Commented Jun 29, 2011 at 0:37

2 Answers 2

2

This is by design, the scrollbar is not part of the client area of a control. It is in the non-client area, similar to caption bar on top of a form. Windows treats them differently, mouse move messages like WM_MOUSEMOVE get announced with WM_NCMOUSEMOVE instead. Winforms does not have events for non-client notifications. This is the way you'd normally want it, you wouldn't want to know about the scrollbar getting manipulated. Feature, not a bug. Except in this case.

As a workaround, you could inherit from ListBox and override WndProc() to see the WM_NCMOUSEMOVE messages (m.Msg == 0xa0). Or a 200 msec Timer that checks where the mouse is located.

Sign up to request clarification or add additional context in comments.

1 Comment

I'm accepting this as the answer, but I have worked around the issue a different way which is sufficient for my purposes. (1) calling Focus() when the user enters the ListBox so they can scroll with the mouse wheel, and (2) using a thread to delay hiding the boxes for about 2.5 seconds.
0

I was struggling with essentially the same (or very similar) problem. Eventually I came up with the following workaround, which I believe actually ends up providing superior functionality in terms of the end-user experience as compared to using MouseLeave. Even if the ListBox didn't have the weird/unexpected behavior with the MouseLeave event, I think this workaround turns out to be a better option anyway.

I still use MouseEnter to enlarge the ListBox. However, instead of having the ListBox shrink back in size with MouseLeave, instead I found it better to actually leave it enlarged until the user clicks anywhere else on the form. I capture the MouseDown event everywhere else on the form, and then shrink the ListBox back to original size when the user clicks anywhere on the form except on the ListBox.

In the form contructor I put this loop:

    foreach (Control control in Controls)
    {
        control.MouseDown += RedirectMouseDown;
    }

Then created this method:

    private void RedirectMouseDown(object sender, MouseEventArgs e)
    {
        Control control = (Control)sender;
        Point screenPoint = control.PointToScreen(new Point(e.X, e.Y));
        Point formPoint = PointToClient(screenPoint);
        MouseEventArgs args = new MouseEventArgs(e.Button, e.Clicks, formPoint.X, formPoint.Y, e.Delta);            
        OnMouseDown(args);
    }

Then inside the form's MouseDown event:

    if (!listBox1.ClientRectangle.Contains(listBox1.PointToClient(Control.MousePosition)))
    {
        if (listBox1.Size.Width == 500)
        {
            listBox1.Size = new Size(listBox1.Size.Width - 200, listBox1.Size.Height);
        }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.