2013-11-28 65 views
0

我有各種基於ToolStripControlHost的自定義上下文菜單。他們被包裹在裏面的ContextMenuStrip並放置在DataGridView中collumns的報頭(在某些條件下),像這樣:GDI對象內存泄漏:ContextMenuStrip中的自定義ToolStripControlHost未配置

 if (this.DGV.Columns[DGVColname] != null) 
     { 
      ContextMenuStrip cstr = null; 
      // there is always only one item in context menu 
      // I tried disposing in different manners, this is an example of my efforts 
      if (this.DGV.Columns[DGVColname].HeaderCell.ContextMenuStrip != null) 
      { 
       cstr = this.DGV.Columns[DGVColname].HeaderCell.ContextMenuStrip; 

       if (cstr.Items[0] != null) 
       { 
        cstr.Items[0].Dispose(); 
        cstr.Items.Clear(); 
       } 
      } 
      else 
      { 
       cstr = new ContextMenuStrip(); 
       cstr.Opened += new EventHandler(cstr_Opened); 
      } 

      TextBoxToolStrip tsHost = new TextBoxToolStrip(); 

      tsHost.Size = new System.Drawing.Size(172, 20); 
      tsHost.TextChanged += new EventHandler(myToolStrip_TextChanged); 

      cstr.ShowCheckMargin = false; 
      cstr.ShowImageMargin = false; 
      cstr.Margin = new Padding(0); 
      cstr.Padding = new Padding(0); 
      cstr.Items.Add(tsHost); 

      cstr.MaximumSize = new Size(tsHost.Width + 10, tsHost.Height + 10); 
      cstr.Size = cstr.MaximumSize; 
      cstr.LayoutStyle = ToolStripLayoutStyle.Flow; 

      DGV.Columns[DGVColname].HeaderCell.ContextMenuStrip = cstr; 
     } 

儘管呼叫處理和/或設置任何我能得到我的手,以空GDI對象計數我的應用程序的成績仍然穩步上升。我在DataGridView中有20列菜單,每次調用代碼時我都會得到+30或+34(正好)。

TextBoxToolStrip在這個例子擴展ToolStripControlHost,並且包含單個文本框:

public class TextBoxToolStrip : ToolStripControlHost 
    { 
     // .... some string or bool Properties here .... 

     public TextBox TextBoxControl 
     { 
      get { return Control as TextBox; } 
     } 

     public TextBoxToolStrip() 
      : base(new TextBox()) 
     { 
      this.TextBoxControl.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
      | System.Windows.Forms.AnchorStyles.Right))); 

      this.TextBoxControl.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; 
      this.TextBoxControl.Location = new System.Drawing.Point(0, 3); 
      this.TextBoxControl.ReadOnly = false; 
      this.TextBoxControl.Font = 
       new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); 

      this.TextBoxControl.Size = new System.Drawing.Size(172, 20); 
      this.Size = new System.Drawing.Size(172, 20); 

      this.TextBoxControl.TabIndex = 0; 
      this.TextBoxControl.TextAlign = System.Windows.Forms.HorizontalAlignment.Left; 

      this.MouseHover += new EventHandler(TextBoxToolStrip_Enter); 

      this.AutoSize = false; 
      this.TextBoxControl.PreviewKeyDown += new PreviewKeyDownEventHandler(TextBoxPreviewKeyDown); 
      this.TextBoxControl.KeyDown += new KeyEventHandler(TextBoxControl_KeyDown); 
     } 

     protected override void OnSubscribeControlEvents(Control control) 
     { 
      base.OnSubscribeControlEvents(control); 

      TextBox tb = control as TextBox; 

      if (tb != null) 
      { 
       tb.TextChanged += new EventHandler(OnTextChanged); 
      } 
     } 

     protected override void OnUnsubscribeControlEvents(Control control) 
     { 
      base.OnUnsubscribeControlEvents(control); 

      TextBox tb = control as TextBox; 

      if (tb != null) 
      { 
       tb.TextChanged -= OnTextChanged; 
      } 
     } 

     private void TextBoxToolStrip_Enter(object sender, EventArgs e) 
     { 
      this.Focus(); 
     } 

     private void TextBoxPreviewKeyDown(object sender, PreviewKeyDownEventArgs e) 
     { 
      if (e.KeyCode == Keys.Menu) 
       e.IsInputKey = true; 
     } 

     private void TextBoxControl_KeyDown(object sender, KeyEventArgs e) 
     { 
      TextBox txb = sender as TextBox; 
      ToolStripDropDown tsd = (ToolStripDropDown)txb.Parent; 

      if (e.KeyCode == Keys.Enter) 
      { 
       tsd.Close(); 
      } 
     } 

     /// <summary> 
     /// Expose TextChanged event 
     /// </summary> 
     public new event EventHandler TextChanged; 

     private void OnTextChanged(object sender, EventArgs e) 
     { 
      if (TextChanged != null) 
      { 
       TextChanged(this, e); 
      } 
     } 

問題:

我怎樣才能妥善處置上下文菜單?

+0

您從不處理CMS本身。 OnSubscribeControlEvents()看起來像是一個很好的GC泄漏源。使用體面的內存分析器。 –

回答

0

原來,它不是事件,靜態引用或任何常用的東西。我有TreeView上的ToolStripControlHosts,結果只有那些泄漏。看來TreeView愉快地泄露了資源:當CheckBoxes屬性設置爲true時,用於繪製已選中和未選中複選框的位圖句柄在處理TreeView時沒有正確釋放(每次在我的TreeView中剩下4個情況),並導致GDI對象內存泄漏。我必須手動處理複選框圖像列表。

該問題和解決方案描述如下here。雖然我在此處使用了屬性而不是事件:

 public new bool CheckBoxes 
     { 
      get 
      { 
       return base.CheckBoxes; 
      } 
      set 
      { 
       if (base.CheckBoxes == false) 
       { 
        base.CheckBoxes = true; 

        IntPtr handle = SendMessage(this.Handle, TVM_GETIMAGELIST, new 
        IntPtr(TVSIL_STATE), IntPtr.Zero); 
         if (handle != IntPtr.Zero) 
          _checkboxImageList = handle; 
       } 
      } 
     } 

StyleChanged事件在我的情況下不起作用。