使 winform 中的所有控件失效会导致无限调用 OnPaint 方法

本文关键字:无限 调用 方法 OnPaint 失效 winform 控件 | 更新日期: 2023-09-27 18:12:51

>我有两个扩展控件。第一个称为LiveControl,它继承自具有调整大小,旋转,移动PictureBox,...方法。第二个称为DrawPanel,它继承自Panel,它意味着几个LiveControl的父级。

我做了几件事来减少滤波,并在一个LiveControl移动到另一个时留下痕迹。 最后,我用LiveControl的以下代码实现了比我预期的更好的结果:

MouseUp += (s, e) =>
{
    foreach (Control c in Parent.Controls.OfType<LiveControl>())
        c.Refresh();
};
MouseMove += (s, e) =>
{
    if (e.Button == MouseButtons.Left)
    {
        Control x = (Control)s;
        x.SuspendLayout();
        x.Location = new Point(x.Left + e.X - cur.X, x.Top + e.Y - cur.Y);
        x.ResumeLayout();
        foreach (Control c in Parent.Controls.OfType<LiveControl>())
            c.Update();
    }
};
protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
    foreach (Control c in Parent.Controls.OfType<LiveControl>())                
        c.Invalidate();                    
}

但问题是,就像上面的代码一样,每个LiveControlOnPaint都会使所有LiveControl无效,它会导致无限的OnPaint调用,从而导致表单上的其他控件出现问题(它们工作非常慢,延迟(。

为了解决这个问题,我像这样编辑了OnPaint的代码:

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
    if (!((DrawPanel)Parent).Invalidating)
    {
        ((DrawPanel)Parent).Invalidating = true;
        ((DrawPanel)Parent).InvalidatedCount = 0;
        foreach (Control c in Parent.Controls.OfType<LiveControl>())                
            c.Invalidate();            
    }
    else
    {
        ((DrawPanel)Parent).InvalidatedCount++;
        if (((DrawPanel)Parent).InvalidatedCount == ((DrawPanel)Parent).Controls.OfType<LiveControl>().Count())
        { 
            ((DrawPanel)Parent).InvalidatedCount = 0; ((DrawPanel)Parent).Invalidating = false;  
        }
    }
}

但是OnPaint方法仍然被称为不间断的方法。有人知道如何解决这个问题吗?

使 winform 中的所有控件失效会导致无限调用 OnPaint 方法

Invalidate触发Paint。在Paint中调用Invalidate是一个无休止的循环。别这样!

如果显示闪烁的所有控件都DoubleBuffering打开,则闪烁将消失。请注意,要打开DoublBuffering您可能需要对其中一些进行子类化,例如PanelsFlowLayoutPanelsDGVs。事实上,只有Form公开它,并且默认情况下只有PictureBox打开它。

您还需要确保消除所有不必要的Invalidates。 - 通常,只有当您在绘图中需要的数据发生变化时,您才需要Invalidate。我在您的代码中根本没有看到任何绘图。否则,您有时可能需要调用Refresh来消除撕裂,即"尾巴"或"痕迹"。

我根本不会处理OnPaint。我想让自定义绘画在 Paint 事件中做到这一点。

你不应该在油漆更新的情况下调用 Invalidate((。如果遇到闪烁问题,是否尝试在自定义控件和容器上将双缓冲设置为 true?

如果通过调用 DrawPanel.Invalidate(( 使 DrawPanel 失效,则一个覆盖具有一个名为 bool invalidateChildren 的标志。您是否尝试过将其设置为真?

希望这会有所帮助。