【问题标题】:Lag between Scroll event and Paint event and maybe something inbetweenScroll 事件和 Paint 事件之间的延迟,可能介于两者之间
【发布时间】:2023-12-29 00:02:01
【问题描述】:

我在表单上有一个简单的面板,我正在使用 AutoScrollMinSize 和 AutoScroll 在我的面板上获取一些滚动条,一切正常。

我还有一个 Scroll 事件,我用它来使整个面板区域无效,因为事实上它似乎只使左/右、上/下滚动时需要的位无效。除此之外,我正在使用与面板大小相同的 BufferedGraphics,然后执行 .Render(e.Graphics) 因为我希望它在整个面板上绘制,就好像滚动条不存在一样.

现在,我遇到的问题是在滚动和绘制内容时似乎存在视觉滞后,我认为这是因为在某个地方有一个额外的绘制/设置阶段,我之前也不熟悉滚动事件被调用或在它和被调用的 Paint 事件之间。

如果我在绘制方法中有一个无效面板,您不会看到问题,但这更多是因为绘制事件被多次调用以隐藏问题。

所以我想我理解的方式是,当你滚动时,引擎盖下的东西会做一个大矩形 blit 移动已经存在的内容,然后用需要填充的区域的矩形调用 invalidate。

如果是这种情况,是否存在这种情况,例如禁止此阶段或我缺少的其他设置以摆脱跟上滞后?

PS:我还重写了 OnPaintBackground 方法,它是一个空存根。

【问题讨论】:

  • 旋转你自己的双缓冲方案并坚持绘制整个面板而不考虑滚动位置是使绘制速度变慢的好方法。只是不要。

标签: c# .net panel autoscroll onpaint


【解决方案1】:

好的,回答我自己的问题,以防它在极少数情况下对您有帮助。从有人提到 LockWindowUpdate 开始,我发现了 WM_SETREDRAW 和这篇文章 SuspendDrawing,现在我可以平滑滚动并能够绘制整个面板。只需让 Scroll 事件执行以下操作。 YMMV。

    [DllImport("user32.dll")]
    private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
    private const int WM_SETREDRAW = 0xB;

    private void PanelView_Scroll(object sender, ScrollEventArgs e)
    {
        Control control = sender as Control;
        if (control!=null)
        {
            if (e.Type == ScrollEventType.ThumbTrack)
            {
                // Enable drawing
                SendMessage(control.Handle, WM_SETREDRAW, 1, 0);
                // Refresh the control 
                control.Refresh();
                // Disable drawing                            
                SendMessage(control.Handle, WM_SETREDRAW, 0, 0);
            }
            else
            {
                // Enable drawing
                SendMessage(control.Handle, WM_SETREDRAW, 1, 0);
                control.Invalidate();
            }
        }
    }

【讨论】: