【问题标题】:Invalidating all controls in a winform causes infinite calls of OnPaint method使winform中的所有控件无效导致无限调用OnPaint方法
【发布时间】:2020-04-12 08:18:46
【问题描述】:

我有两个扩展控件。 第一个称为LiveControl,它继承自PictureBox,它具有调整大小、旋转、移动...方法。 第二个称为DrawPanel,它继承自Panel,它是多个LiveControls 的父代。

当一个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 都会使所有LiveControls 无效,它会导致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 方法仍然被不间断地调用。 有人知道如何解决这个问题吗?

【问题讨论】:

  • downvoter,你能说一下为什么吗?
  • 尝试在 OnPaint 事件上分离绘画事件,并在完成任务后在控件上再次注册它。这可能会帮助您克服无限循环
  • @NiranjanKala 如果我分离 OnPaint 事件,Invalidate() 不会有任何好处。
  • 由于Invalidate 导致Paint,从OnPaint 调用Invalidate 不是一个好主意。您真正想用该代码实现什么目标?
  • 不是我的反对意见,但有一个明显的无限循环表明缺乏研究。 - 在 Paint 中调用 Invalidate 是一个无限循环。期间。

标签: c# winforms


【解决方案1】:

Invalidate 触发 Paint 。在Paint 中调用Invalidate 是一个无限循环。不要那样做!

如果显示闪烁的所有控件都打开了DoubleBuffering,闪烁将会消失。 注意要打开DoublBuffering,您可能需要子类化其中一些,例如PanelsFlowLayoutPanelsDGVs.. 实际上只有@987654330 @ 暴露它,只有 PictureBox 默认开启它。

您还需要确保消除所有不必要的 Invalidates。 - 通常你需要Invalidate,只有当你在绘图中需要的数据已经改变了。我根本没有在您的代码中看到 any 绘图。否则您有时可能需要致电Refresh 来消除撕裂,即“尾巴”或“痕迹”。

【讨论】:

    【解决方案2】:

    我根本不会处理 OnPaint。我想在 Paint 事件中进行自定义绘制。

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

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

    希望这会有所帮助。

    【讨论】:

    • 我已经尝试过DoubleBuffered,它让结果变得更糟。在其他控件上留下痕迹。 DrawPanel.Invalidate(),将 invalidateChildren 设置为 true 与使所有子级无效并且也使父级无效的作用相同。我会尝试在 Paint 事件中处理它,看看会发生什么。
    • @AshkanMobayenKhiabani:那么我认为你在其他地方遇到了严重的麻烦。我已经做了很多次你正在做的事情,没有任何问题,只是让 Windows 处理绘画、无效等。而不是从 Panel 派生,你是否尝试从 UserControl 派生,你可以将你的 PictureBox 派生到 UserControl也一样?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-14
    • 2023-02-17
    • 1970-01-01
    • 2016-06-02
    • 1970-01-01
    相关资源
    最近更新 更多