Search code examples
c#winformsscrollbar

How can automatic rearrangement of elements on the control be prevented when AutoScroll option is on?


Context:
I have a main user control which contains a window and an instance of another (different) user control in it. In a window I am displaying an object which can be zoomed. For the zoom I am using the mouse wheel. Outside this window, mouse wheel controls page scrolling, and because of that, when my mouse is inside the window and when AutoScroll option of the main control is set to True, both actions happen at the same time (object moves and page scrolls). So I disable AutoScroll when the mouse position is inside the window and enable it again when the mouse leaves the window.

Problem:
When the mouse is leaving the window, elements on the form automatically reposition (before and after on the images below).

What I've tried so far:
I tried to change the position of each element after this automatic change, and the final result is okay, but I can't avoid the delay between the two "events" (automatic position change and manual position change) so I get a flash of the automatically repositioning in between. This shift also happens when I leave scrollbar shown even when it is disabled (as a placeholder) - but then the buttons on the right don't move, just the form in the middle lowers as on the image.

I also tried skipping the first OnPaint event after switching between the window and the main form, but the problem remains.

ImageBeforeRearrangement: ImageBeforeRearrangement

ImageAfterRearrangement: ImageAfterRearrangement


Solution

  • Allow and disallow scrolling on your form or user control depending on the mouse position:

        private void ucSomething_MouseEnter(object sender, EventArgs e)
        {
            bScrollAllowed = true;
        }
    
        private void ucSomething_MouseLeave(object sender, EventArgs e)
        {
            bScrollAllowed = false;
        }
    

    And then block the Windows message depending on the bScrollAllowed field:

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x20a && !bScrollAllowed)
            {
                return;
            }
            base.WndProc(ref m);
        }