【问题标题】:C# - Custom TabControl Class Memory Leak onHoverC# - 自定义 TabControl 类内存泄漏 onHover
【发布时间】:2017-08-24 03:35:47
【问题描述】:
#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

我有这个更现代的自定义选项卡控件类,它是左对齐而不是顶部对齐。它可以工作,但是存在巨大的内存泄漏问题。我正在使用MouseMove 来获取鼠标位置,然后将其与选项卡交叉匹配,但即使我将鼠标保持不动或移动到选项卡的中间位置,它显然会执行数百万有时,这会导致内存使用量激增。

有没有办法解决这个问题?

Process Memory Diagnostic

【问题讨论】:

    标签: c# memory memory-management memory-leaks


    【解决方案1】:

    在 OnMouseMove 中的 for 循环之后缓存鼠标坐标。然后,在 for 循环之前,根据当前坐标检查缓存的坐标。如果它们的差异低于您选择的阈值,请退出该功能。使用这种方法只会在鼠标位置发生重大变化时执行您的逻辑。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 2011-10-02
        • 2018-07-15
        • 1970-01-01
        • 2011-07-05
        • 1970-01-01
        • 2016-07-04
        • 2012-04-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多