1

Moving Label inside parent's MouseMove-events causes trailing redraw.

I am (mis)using System.Windows.Forms.Label objects to realize

  1. A more flexible tooltip,
  2. Displaying a cross hair "cursor" extending to the borders of a parent control.

To that end I create the labels as members of the parent control (btw. it's a custom graphics control with mouse wheel zoom, panning etc.), add them to the parent's Controls-list, and move them inside the MouseMove-event of the parent. In order to ensure crisp movement behavior, I even call Label.Refresh when assigning the Location property of the Labels.

    void GraphViewMouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        if (lastLocation != e.Location)
        {
            HasMoved = true;

            if (IsPanning && e.Button == MouseButtons.Left) 
            {
                if (isSelecting) PerformSelection(e.Location);
                else PerformMove(e.Location,lastLocation);          
            }
            lastLocation = e.Location;

            if (Width > 0 && Height > 0)
            {
                PointD pos = CursorPosition;
                // nothing interesting, basically like what is done with the crossHair's below
                coordinateToolTip.Locate(lastLocation, pos.X, pos.Y);

                crossHairX.Location = new Point(lastLocation.X, 0);
                crossHairY.Location = new Point(0, lastLocation.Y);
                crossHairX.Refresh();
                crossHairY.Refresh();
            }
        }
    }

Everything works almost fine (the labels move parallel to the mouse cursor) except that when I move the mouse a little faster, several copies of the Label(s) remain in the client area of the parent for some time like a visual echo.

That is, whereas the redraw of the labels at their new location appears to occur immediately, it seems to take some fraction of a second until the background of the parent (some complicated graphics, the complete redraw of which takes several seconds, but is definitely not redrawn during said simple mouse move) is restored to what has been behind the moving Label(s) originally. This is of course functionally irrelevant, but it simply looks ugly because it raises the impression that the code is inefficient.

Is there a way to enforce (faster) redraw of the cached background graphics? What determines the delay before the screen content behind a control is restored?

Edit: as to the suggestion of setting DoubleBuffered=true: according to MSDN this should already be true by default. Indeed it doesn't make a difference if I set it true for the Label. On the other hand, setting it false introduces additional flickering as expected. In either case the restoration of the background remains delayed, like described above.

oliver
  • 2,771
  • 15
  • 32
  • When you move a control, its parent's OnPaintBackground() method needs to run to over-draw the pixels that were left behind by the control in its previous position. If that involves "complicated graphics" then, sure, that takes a while and you can see those stale pixels before they get repainted. The visual effect is a "smear", the human eye is very sensitive to it. Amortize expensive painting code by drawing into a bitmap. Getting rid of it completely [requires compositing](https://stackoverflow.com/a/3718648/17034). – Hans Passant Oct 01 '17 at 10:21
  • @Hans Passant: thanks for your help! I have not been aware of the fact that moving a child control causes a complete redraw of the parent. Indeed I have confirmed that for my code. I was thinking that the screen content would be cached, similar to what happens when a different window gets to the foreground. I will further investigate your proposed solutions. – oliver Oct 01 '17 at 14:25
  • PS: the compositing solution worked perfectly (in my case on Windows 10)! I consider the issue as solved. – oliver Oct 01 '17 at 16:49

1 Answers1

0

@Hans Passant: Thanks for telling us "When you move a control, its parent's OnPaintBackground() method needs to run to over-draw the pixels that were left behind by the control in its previous position."

For me the cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED did not work. I am creating movable, Resizable Panel and when I moved it fast from left to right it was not displayed right "the half of the panel was often gone". I did this and now it works exactly like when I move a Windows Window.

This is in the MyPanel Class which I made and Inherits from Panel

        protected override void OnMove(EventArgs e)
        {
            this.Parent.Invalidate();
            base.OnMove(e);

        }

So when I move the Movable panel with the mouse it wil Invalidate the "Parrent" in my case the Form and now it moves fine.

Stefan27
  • 845
  • 8
  • 19