简体   繁体   中英

C# - Custom TabControl Class Memory Leak onHover

#region CustomTabControl - Leak

public class cTabControl : TabControl
{

    #region Remove Padding
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x1300 + 40)
        {
            lparamrect rc = (lparamrect)m.GetLParam(typeof(lparamrect));
            rc.Left -= 4;
            rc.Right += 4;
            rc.Top -= 2;
            rc.Bottom += 4;
            Marshal.StructureToPtr(rc, m.LParam, true);
        }
        base.WndProc(ref m);
    }
    internal struct lparamrect
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }
    #endregion

    //Variables;
    private Rectangle Rect;
    private int _OverIndex = -1;
    private int OverIndex
    {
        get { return _OverIndex; }
        set
        {
            _OverIndex = value;
            Invalidate();
        }
    }

    //Default Settings;
    public cTabControl()
    {
        DoubleBuffered = true;
        Alignment = TabAlignment.Left;
        SizeMode = TabSizeMode.Fixed;
        ItemSize = new Size(30, 32);
    }

    protected override void OnCreateControl()
    {
        base.OnCreateControl();
        SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true);
    }

    protected override void OnControlAdded(ControlEventArgs e)
    {
        base.OnControlAdded(e);
        e.Control.BackColor = Settings.Default.TabBackgroundColor;
        e.Control.ForeColor = ColorFromHex("#FFFFFF");
        e.Control.Font = new Font("Kozuka Gothic Pro B", 9);
    }

    protected override void OnPaint(PaintEventArgs e)
    {

        //Set the Graphics Variable;
        Graphics G = e.Graphics;

        //Raise the Paint event;
        base.OnPaint(e);

        //Dynamically Darken the Parent's Color slightly;
        Color DarkParentColor = default(Color);
        if (ColorContrast(Parent.BackColor) == Color.White)
        {
            DarkParentColor = ControlPaint.Light(ControlPaint.Dark(Parent.BackColor, (float)0.01), (float)1.2);
        }
        else
        {
            DarkParentColor = ControlPaint.Light(ControlPaint.Dark(Parent.BackColor, (float)0.1), (float)0.35);
        }

        //Set the Tab's Background Color to the Darkened Parent's Color;
        G.Clear(DarkParentColor);

        //For Each Tab;
        for (int i = 0; i <= TabPages.Count - 1; i++)
        {

            if ((string)TabPages[i].Tag != "Hidden")
            {

                // Get the Tab's Rectangle Sizing
                Rect = GetTabRect(i);
                float x = Convert.ToSingle((Rect.X + (Rect.Height - 10)) - (Rect.Height / 2));
                float y = Convert.ToSingle((Rect.Y + (Rect.Height - 10)) - (Rect.Height / 2));

                // If the user is hovering over the tab
                if (!(OverIndex == -1))
                {
                    using (SolidBrush sb = new SolidBrush(Color.FromArgb(9, Color.Black)))
                    {
                        //Draw the Hover Background;
                        G.FillRectangle(sb, new Rectangle(GetTabRect(OverIndex).X, GetTabRect(OverIndex).Y, GetTabRect(OverIndex).Width, GetTabRect(OverIndex).Height));
                    }
                }
                else
                {
                    using (SolidBrush sb = new SolidBrush(DarkParentColor))
                    {
                        // Set the Background Color to the Darkened Parent's Color
                        G.FillRectangle(sb, new Rectangle(Rect.X, Rect.Y, Rect.Width + 6, Rect.Height));
                    }
                }

                // If its the selected tab
                if (SelectedIndex == i)
                {
                    using (SolidBrush sb = new SolidBrush(Settings.Default.HighlightColor), sb2 = new SolidBrush(Color.FromArgb(30, Color.Black)))
                    {
                        // Set the Selected Indicator to the Highlight Color
                        G.FillRectangle(sb, new Rectangle(Rect.X, Rect.Y, 2, Rect.Height));
                        //Draw the Hover Background;
                        G.FillRectangle(sb2, new Rectangle(Rect.X, Rect.Y, Rect.Width, Rect.Height));
                    }
                }

                //Set Render Quality;
                G.TextRenderingHint = TextRenderingHint.AntiAlias;

                if ((!ReferenceEquals(Tag, "TextOnly")))
                {
                    if (!(SelectedIndex == i))
                    {
                        using (Graphics gfx = Graphics.FromImage(new Bitmap(GetTabIcon(i).Width, GetTabIcon(i).Height)))
                        {
                            ColorMatrix matrix = new ColorMatrix();
                            matrix.Matrix33 = (float)0.5;
                            ImageAttributes attributes = new ImageAttributes();
                            attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
                            G.DrawImage(GetTabIcon(i), new Rectangle(Convert.ToInt32(x), Convert.ToInt32(y), 20, 20), 0, 0, GetTabIcon(i).Width, GetTabIcon(i).Height, GraphicsUnit.Pixel, attributes);
                        }
                    }
                    else if (SelectedIndex == i)
                    {
                        using (Image ti = GetTabIcon(i))
                        {
                            G.DrawImage(ti, new Rectangle(Convert.ToInt32(x) + 1, Convert.ToInt32(y), 20, 20));
                        }
                    }
                }
                else
                {
                    dynamic TabProperties = TabPages[i];
                    StringFormat sf = new StringFormat();
                    sf.LineAlignment = StringAlignment.Center;
                    using (Font f = new Font(LoadFont(Resources.Roboto_Medium), 10f))
                    using (SolidBrush sb = new SolidBrush(TabProperties.ForeColor))
                    {
                        G.DrawString(TabProperties.Text, f, sb, x + 2, Convert.ToSingle(Rect.Y + (Rect.Height / 2)), sf);
                    }
                }

            }

        }

    }

    protected override void OnSelecting(TabControlCancelEventArgs e)
    {
        base.OnSelecting(e);

        if ((e.TabPage != null))
        {
            if (!string.IsNullOrEmpty(Convert.ToString(e.TabPage.Tag)))
            {
                e.Cancel = true;
            }
            else
            {
                OverIndex = -1;
            }
        }

    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e);

        for (int I = 0; I <= TabPages.Count - 1; I++)
        {
            if (GetTabRect(I).Contains(e.Location) & string.IsNullOrEmpty(Convert.ToString(TabPages[I].Tag)))
            {
                OverIndex = I;
                break; // TODO: might not be correct. Was : Exit For
            }
            else
            {
                OverIndex = -1;
            }
        }

    }

    protected override void OnMouseLeave(EventArgs e)
    {
        base.OnMouseLeave(e);
        OverIndex = -1;
    }

}

#endregion

I have this custom tab control class that is more modern and is left aligned rather than top aligned. It works, but there's a huge memory leak issue with it. I'm using MouseMove to be able to get the mouse location and then cross match it with the tabs, but even if I leave my mouse still or move in more to the middle of the tab for example, it will obviously execute millions of times, this then causes huge spikes in memory usage.

Is there any way around this?

Process Memory Diagnostic

cache the mouse-coordinates after the for-loop in your OnMouseMove. then, before the for-loop, check the cached coodinates against the current coordinates. if their difference is lower then a treshold of your choice, exit the function. using this approach will execute your logic only on major changes to the mouse-position.

看来发生这种情况的原因是因为对于TextOnly,它正在使用LoadFont gdi32.dll加载Roboto,并且由于某种原因,它需要使用大量资源进行加载,从而完全删除了所有LoadFont()并然后在GetTabIcon()的位图上添加using()使其完全稳定!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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