1

長時間のプロセスに使用されるカスタム コントロールがあります。このコントロールには、ポイントの周りに回転する円があります。これを行うために、設計時と実行時に動作するタイマーを使用しています。フォームに 1 つのコントロールを追加する場合は問題ありません。しかし、それらのうちの2つがフォームに追加されると、デザイナーは非常に遅くなります。なぜこの問題が発生し、どうすれば修正できますか?

このプロジェクトの私のコード:

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

1 に答える 1

1

なぜこの問題が発生し、どうすれば修正できますか?

この問題は、設計時間とタイマーに共通するものは何もありませんが、MakeTransparentメソッドの実装が正しくありません。

まず、状態に明らかなバグがあります

c.Bounds.IntersectsWith(c.Bounds)

このバグの影響は、呼び出し元以外の各コントロールc.DrawToBitmap呼び出すことです。しかし、DrawToBitmapトリガーOnPaintは であるため、他のコントロールもSpinningCirclesである場合、同じことを行うため、現在の呼び出し元にヒットし、無限OnPaintサイクルになります。

意図した状態での修正

c.Bounds.IntersectsWith(cont.Bounds)

2 つのカスタム コントロールが重ならなくなり次第、問題を修正します。

実装全体が正しくありません。そもそもやるべきではありませんが、一度やったら、少なくとも呼び出し元とDrawToBitmap交差し、ZOrder が低いコントロールのみを呼び出す必要があります。このようなもの:

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();
}
于 2016-03-24T11:53:00.663 に答える