简体   繁体   English

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

[英]Invalidating all controls in a winform causes infinite calls of OnPaint method

I have two Extented controls.我有两个扩展控件。 First one is called LiveControl which is inherited from PictureBox which have Resizing,Rotation, Move,... Methods.第一个称为LiveControl ,它继承自具有调整大小、旋转、移动...方法的PictureBox Second one is called DrawPanel which is inherited from Panel which is meant to be the parent for several LiveControl s.第二个叫做DrawPanel ,它是从Panel继承的,它是几个LiveControl的父LiveControl

I did several things to reduce filckering and also leaving trails when one LiveControl moved over another.当一个LiveControl移到另一个LiveControl时,我做了几件事来减少闪烁并留下痕迹。 and finally I achieved it even better than I expected with the following codes in 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();                    
}

But the problem is that as in the above code, each LiveControl 's OnPaint invalidates all of the LiveControl s, it causes infinite calls of OnPaint which causes problems for other controls on the form (they work very slow with delays).但问题是,在上面的代码中,每个LiveControlOnPaint使所有LiveControl都无效,它会导致对OnPaint无限调用,从而导致表单上的其他控件出现问题(它们的工作速度非常慢且有延迟)。

To solve this I edited the code for OnPaint like this:为了解决这个问题,我像这样编辑了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;  
        }
    }
}

But the OnPaint method is still being called nonstop.但是OnPaint方法仍在不停地调用。 Does anybody has any idea how to solve this?有谁知道如何解决这个问题?

Invalidate triggers Paint . Invalidate触发Paint Calling Invalidate in Paint is an endless-loop.Paint调用Invalidate是一个无限循环。 Don't do that!不要那样做!

Flicker will go away if all controls that show it have DoubleBuffering on.如果所有显示它的控件都DoubleBuffering ,则闪烁将消失。 Note that to turn on DoublBuffering you may need to subclass some of them, like Panels , FlowLayoutPanels or DGVs .. In fact only Form exposes it and only PictureBox has it on by default.请注意,要打开DoublBuffering您可能需要对其中一些进行子类化,例如PanelsFlowLayoutPanelsDGVs .. 事实上,只有Form公开它,并且默认情况下只有PictureBox将其打开。

You also need to make sure all unnecessary Invalidates are eliminated.您还需要确保消除所有不必要的Invalidates - Usually you need Invalidate only when data you need in drawing have changed . - 通常只有在绘图中需要的数据发生变化时才需要Invalidate I don't see any drawing in your code at all.我在您的代码中根本看不到任何绘图。 Otherwise you sometimes may need to call Refresh to eliminate tearing , ie 'tails' or 'traces'.否则,您有时可能需要调用Refresh来消除撕裂,即“尾部”或“痕迹”。

I would not deal with OnPaint at all.我根本不会处理 OnPaint。 I you want to make custom paint do it in the Paint event.我想在 Paint 事件中自定义绘制。

You should never call Invalidate() in a paint update situation.在绘制更新的情况下,您永远不应该调用 Invalidate()。 If you have problems with flicker have you tried to set DoubleBuffered to true on your custom controls and container?如果您遇到闪烁问题,是否尝试在自定义控件和容器上将 DoubleBuffered 设置为 true?

If you invalidate DrawPanel by calling DrawPanel.Invalidate() one override has a flag called bool invalidateChildren .如果您通过调用 DrawPanel.Invalidate() 使 DrawPanel 无效,则覆盖有一个名为bool invalidateChildren的标志。 Have you tried to set that to true?您是否尝试将其设置为 true?

Hope this will help.希望这会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM