I have a custom control that is used for long time processes. This control has spinning circles around a point. To do this, I am using timer that is working on design time and run-time. When one control is added to form there is no problem. But two of them are added to form, the designer slows down so much. Why does this problem occurs and how can I fix it?
My code from this project:
public class SpinningCircles : Control
{
bool fullTransparency = true;
int increment = 1;
int radius = 4;
int n = 8;
int next = 0;
int k = 0;
Timer timer;
public SpinningCircles()
{
timer = new Timer();
timer.Tick += timer_Tick;
timer.Enabled = true;
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.UserPaint | ControlStyles.SupportsTransparentBackColor, true);
BackColor = Color.Transparent;
}
void timer_Tick(object sender, EventArgs e)
{
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
if (fullTransparency)
{
Transparencer.MakeTransparent(this, e.Graphics);
}
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
int length = Math.Min(Width, Height);
PointF center = new PointF(length / 2, length / 2);
int bigRadius = length / 2 - radius - (n - 1) * increment;
float unitAngle = 360 / n;
next++;
next = next >= n ? 0 : next;
int a = 0;
for (int i = next; i < next + n; i++)
{
int factor = i % n;
float c1X = center.X + (float)(bigRadius * Math.Cos(unitAngle * factor * Math.PI / 180));
float c1Y = center.Y + (float)(bigRadius * Math.Sin(unitAngle * factor * Math.PI / 180));
int currRad = radius + a * increment;
PointF c1 = new PointF(c1X - currRad, c1Y - currRad);
e.Graphics.FillEllipse(Brushes.Black, c1.X, c1.Y, 2 * currRad, 2 * currRad);
using (Pen pen = new Pen(Color.White, 2))
e.Graphics.DrawEllipse(pen, c1.X, c1.Y, 2 * currRad, 2 * currRad);
a++;
}
}
protected override void OnVisibleChanged(EventArgs e)
{
timer.Enabled = Visible;
base.OnVisibleChanged(e);
}
public bool FullTransparent
{
get
{
return fullTransparency;
}
set
{
fullTransparency = value;
}
}
}
public class Transparencer
{
public static void MakeTransparent(Control cont, Graphics g)
{
if (cont.Parent != null)
{
Bitmap behind = new Bitmap(cont.Parent.Width, cont.Parent.Height);
foreach (Control c in cont.Parent.Controls)
if (c.Bounds.IntersectsWith(c.Bounds) & c != cont)
c.DrawToBitmap(behind, c.Bounds);
g.DrawImage(behind, -cont.Left, -cont.Top);
behind.Dispose();
}
}
}
The problem has nothing in common with design time and timers, but the incorrect implementation of your
MakeTransparent
method.First, there is an obvious bug in the condition
The affect of this bug is the it calls
c.DrawToBitmap
for each control other than the caller. ButDrawToBitmap
triggersOnPaint
, so when the other control is alsoSpinningCircles
, it does the same, so it hits the current caller and you end up with an infiniteOnPaint
cycle.Fixing the condition with the intended
will fix the issue as soon as the two custom controls do not overlap.
The whole implementation is incorrect. You shouldn't be doing it at the first place, but once you did it, it should at least call
DrawToBitmap
only for controls that intersect with the caller and has lower ZOrder. Something like this: