Window 拖过 UserControl 后 GDI+ 中的拖尾现象

Smearing Phenomenon in GDI+ After a Window is Dragged Over the UserControl

我正在创建一个 UserControl,我想通过 ControlPaint.DrawBorder() 给它添加一个边框。
我为 OnPaint() 创建了一个覆盖,并将其放入其中:

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);


    int     Border_Width    =1;
    Color   Border_Color    =Color.FromArgb(170,170,170);

    ControlPaint.DrawBorder(e.Graphics,e.ClipRectangle,
        Border_Color,Border_Width,ButtonBorderStyle.Solid,      //Left
        Border_Color,Border_Width,ButtonBorderStyle.Solid,      //Top
        Border_Color,Border_Width,ButtonBorderStyle.Solid,      //Right
        Border_Color,Border_Width,ButtonBorderStyle.Solid);     //Bottom
}

边框画的很好,但是自从我加上了,问题就来了:

每当我将其他一些 window 拖到该用户控件上时,我会在用户控件上出现 "leftover" 污迹..

看看它的样子:

覆盖 OnPaint() 之前:

覆盖 OnPaint() 后:

为什么会这样?

根据我的实验,
尝试启用 DubbleBuffering 在这里没有帮助.. 涂抹仍然存在..

此外,如果我禁用 ControlPaint.DrawBorder() 行,
并将其替换为 e.Graphics.DrawRectangle(),
然后问题就消失了..

所以这意味着问题不一定在于覆盖 OnPaint() 或类似的东西,而是 ControlPaint.DrawBorder().

ControlPaintclass在它提供的其他绘图操作中是否有问题?
是否有解决办法,或者由于这个错误应该避免它?

看来你是用cliprect画边框的,意思就是只重绘控件的部分。使用控件dimensions/coordinates绘制边框

你误解了e.ClipRectangle的作用。它与你的window内容无关,它只是告诉你你的window的哪一部分需要重新绘制。您代码中的错误仅在 XP 上非常明显,在使用 Aero 的较新 Windows 版本上更不明显。

当您将另一个 window 拖过您的 OS 时,OS 会告诉您只需要重绘 window 移动时显示的部分。只是一条细长条,如果您水平拖动,那么它的宽度只会与自上次您绘制后用户移动 window 的宽度一样宽。 e.ClipRectangle 包含该条子。

旨在帮助您优化您的绘画代码。由于您只需绘制那条条子,因此您可以跳过在它之外绘制的任何代码。优化您的绘画代码可能很重要,如果它太慢,那么用户可以看到条子的未绘画部分,并产生类似于您在启用鼠标轨迹时看到的视觉效果。然而,Windows 本身已经优化以在内部观察 ClipRectangle。您仍然进行 Graphics 方法调用,但它们什么都不做。或者只做你要求他们做的工作的一部分,与 ClipRectangle 相交的部分。因此,实际上很少需要编写代码并针对矩形进行测试。

您的错误在 Aero 上不太明显,它 double-buffers 内存中的 window 表面。更接近于许多程序员认为绘画应该起作用的方式。它可以非常快速地从表面副本中重新绘制条子,而无需您提供帮助。但是,当您将 window 拖出屏幕并返回时,它仍然会发生,double-buffered 表面不包括不在屏幕上的 window 部分。