当添加了两个自定义控件时,为什么设计器会变慢? [英] Why does the designer slowing when two custom controls has timer added?

查看:88
本文介绍了当添加了两个自定义控件时,为什么设计器会变慢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用于长时间过程的自定义控件。该控件在一个点周围有旋转的圆圈。为此,我使用的计时器正在设计时间和运行时。将一个控件添加到窗体中就没有问题。但是其中两个被添加到窗体中,设计师的速度变慢了很多。为什么会发生此问题,我该如何解决?

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();
        }
    }
}


推荐答案


为什么会出现此问题,我该如何解决?

Why does this problem occurs and how can I fix it?

问题不存在与设计时间和计时器相同,但是 MakeTransparent 方法的错误实现。

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

c.Bounds.IntersectsWith(c.Bounds)

此错误的影响是它为每个调用 c.DrawToBitmap DrawToBitmap 会触发 OnPaint ,因此当另一个控件也是 SpinningCircles ,它执行相同的操作,因此它会击中当前呼叫者,您最终会遇到无限的 OnPaint 周期。

The affect of this bug is the it calls c.DrawToBitmap for each control other than the caller. But DrawToBitmap triggers OnPaint, so when the other control is also SpinningCircles, it does the same, so it hits the current caller and you end up with an infinite OnPaint cycle.

用预期的条件解决条件

c.Bounds.IntersectsWith(cont.Bounds)

将在两个自定义控件不重叠时立即解决此问题。

will fix the issue as soon as the two custom controls do not overlap.

整个实现都不正确。您不应该一开始就这样做,但是一旦完成,它至少应该只对与调用方相交且具有控制权的控件调用 DrawToBitmap 降低ZOrder 。像这样的东西:

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:

public static void MakeTransparent(Control control, Graphics g)
{
    var parent = control.Parent;
    if (parent == null) return;
    var bounds = control.Bounds;
    var siblings = parent.Controls;
    int index = siblings.IndexOf(control);
    Bitmap behind = null;
    for (int i = siblings.Count - 1; i > index; i--)
    {
        var c = siblings[i];
        if (!c.Bounds.IntersectsWith(bounds)) continue;
        if (behind == null)
            behind = new Bitmap(control.Parent.ClientSize.Width, control.Parent.ClientSize.Height);
        c.DrawToBitmap(behind, c.Bounds);
    }
    if (behind == null) return;
    g.DrawImage(behind, control.ClientRectangle, bounds, GraphicsUnit.Pixel);
    behind.Dispose();
}

这篇关于当添加了两个自定义控件时,为什么设计器会变慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆