0

I have two Extented controls. First one is called LiveControl which is inherited from PictureBox which have Resizing,Rotation, Move,... Methods. Second one is called DrawPanel which is inherited from Panel which is meant to be the parent for several LiveControls.

I did several things to reduce filckering and also leaving trails when one LiveControl moved over another. and finally I achieved it even better than I expected with the following codes in 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 LiveControls, it causes infinite calls of OnPaint which causes problems for other controls on the form (they work very slow with delays).

To solve this I edited the code for OnPaint like this:

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. Does anybody has any idea how to solve this?

Imran Sh
  • 1,623
  • 4
  • 27
  • 50
Ashkan Mobayen Khiabani
  • 33,575
  • 33
  • 102
  • 171
  • downvoter, would you please say why? – Ashkan Mobayen Khiabani Oct 12 '16 at 05:38
  • try to detach paint event on the OnPaint event and after completing the task register it again on the control.. that may help you to overcome from infinite loop – Niranjan Singh Oct 12 '16 at 05:40
  • @NiranjanKala if I detach the OnPaint event, the `Invalidate()` won't do any good. – Ashkan Mobayen Khiabani Oct 12 '16 at 05:44
  • 1
    Since `Invalidate` is causing `Paint`, calling `Invalidate` from `OnPaint` is not a good idea. What really are you trying to achieve with that code? – Ivan Stoev Oct 12 '16 at 07:01
  • Not my down-vote, but having an obvious endless loop shows a lack of research. - Calling Invalidate in Paint is an endless-loop. Period. – TaW Oct 12 '16 at 07:17
  • I couldn't see any flickering in the solution which I proposed for your [previous question](http://stackoverflow.com/q/39948820/3110834). Did you try that? B the way, surely invalidating in paint event is not a good idea. – Reza Aghaei Oct 12 '16 at 11:36

2 Answers2

2

Invalidate triggers Paint . Calling Invalidate in Paint is an endless-loop. Don't do that!

Flicker will go away if all controls that show it have DoubleBuffering on. 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.

You also need to make sure all unnecessary Invalidates are eliminated. - Usually you need Invalidate only when data you need in drawing have changed. I don't see any drawing in your code at all. Otherwise you sometimes may need to call Refresh to eliminate tearing, i.e. 'tails' or 'traces'.

TaW
  • 53,122
  • 8
  • 69
  • 111
1

I would not deal with OnPaint at all. I you want to make custom paint do it in the Paint event.

You should never call Invalidate() in a paint update situation. If you have problems with flicker have you tried to set DoubleBuffered to true on your custom controls and container?

If you invalidate DrawPanel by calling DrawPanel.Invalidate() one override has a flag called bool invalidateChildren. Have you tried to set that to true?

Hope this will help.

  • I have tried `DoubleBuffered` it is making the result worse. leaving trails all over the other controls. `DrawPanel.Invalidate()`, with `invalidateChildren` set to true does the same thing as invalidates all children and also invalidates the parent too. I'll try dealing with it in Paint event to see what happens. – Ashkan Mobayen Khiabani Oct 12 '16 at 06:27
  • @AshkanMobayenKhiabani: Then I think you are in serious trouble somewhere else. I have done what you are doing lots of times without any problems just letting Windows take care of paint, invalidate etc. Instead of derive from Panel, have you tried to derive from UserControl, and you could maybe put your PictureBox-derive into a UserControl as well? –  Oct 12 '16 at 07:00