2014-02-19 91 views
0

我使用XML文件的條目填充ToolStripMenu。添加到菜單中的每個ToolStripItem會自動獲取大約12個分配給它的事件處理程序。用戶必須改變XML並刷新菜單,使用它會清除所有的選項:爲動態創建的項目發佈事件處理程序

menuStrip1.Items.Clear(); 

這重新填充來自XML並刷新表格。看來,所有這些動態項目的事件處理程序都不會從內存中刪除。大多數項目不直接坐在menuStrip1上,而是在menuStrip1上動態創建的子菜單中。不過,我可以坐在那裏刷新表格和內存,只是氣球失去控制,每增加約100 dynamic ToolStripItems.就會增加5-10 MB它可以快速達到數百MB,這會使應用程序崩潰。

ToolStripItems也加載其他東西,如屬性和圖標,但它似乎是使用大部分增加的內存的事件處理程序。我評論了所有的處理程序,每次刷新後內存變得更多(但不是完全)可持續。

是否有必要枚舉所有的菜單和子菜單,並單獨釋放每個事件處理程序以確保它不會粘住?

+1

你可能應該在每一個上調用Dispose來釋放他們的資源。 – tvanfosson

+1

如果您處理/刪除事件處理程序*和*它所訂閱的對象,則應該是正常的。否則,是的,你可能不得不取消訂閱每個處理程序(或者看看不同的訂閱方式 - 而不是編譯器生成的事件) –

+1

你可能想要查看[弱事件模式](http://msdn.microsoft.com/ 。com/en-us/library/aa970850%28v = vs.110%29.aspx) –

回答

1

如果您處置/刪除事件處理程序和它所訂閱的對象,則應該沒問題。否則,是的,你將不得不退訂每個處理程序。

或者看看不同的訂閱方式 - 而不是編譯器生成的事件。例如http://paulstovell.com/blog/weakevents

0

檢查菜單條的ItemRemoved事件。它會返回一個從菜單條中刪除的項目。你可以在這裏處理它,或者你可以從這裏刪除每個處理程序。

修訂

一旦你的父菜單,那麼你可以通過使用遞歸函數調用中刪除所有子菜單的事件處理程序。

private void menuStrip1_ItemRemoved(object sender, ToolStripItemEventArgs e) 
{ 
    foreach (object child in ((ToolStripMenuItem)e.Item).DropDownItems) 
    { 
     if (child.GetType().Name == "ToolStripMenuItem") 
      RemoveHandler((ToolStripMenuItem)child);     
    } 
} 
private void RemoveHandler(ToolStripMenuItem item) 
{ 
    if (item.HasDropDownItems) 
    { 
     foreach (Object dropdown in item.DropDownItems) 
     { 
      if (dropdown.GetType().Name == "ToolStripMenuItem") 
       RemoveHandler((ToolStripMenuItem)dropdown); 
     } 
    } 
    else 
    { 
     //item.Click -= new EventHandler(MenuItem_Clicked); 
     //Remove event handlers 
    } 
} 
+0

感謝您的建議,但這隻會直接觸發menuStrip1上的菜單,它實際上是菜單和子菜單中具有所有事件處理程序的項目。現在我唯一發現的是遞歸地遍歷菜單層次結構並單獨處理每個項目,因爲每個菜單都有幾個不同類型的ToolStripItems,這是一個令人頭痛的問題。 – KevinD

+0

我更新在我的答案中添加了一個示例。 – Shell

0

,我經常使用的是創建一個private _cleanUp = New List<Action>()類級變量和使用該清理事件處理程序的一個小竅門。

所以,當我附上一個事件處理程序我也是分離的代碼添加到列表中,像這樣:

this.NameTextbox.Click += My_Handler; 
_cleanUp.Add(() => this.NameTextbox.Click -= My_Handler); 

然後在清理,爲您的代碼,我可以做到這一點:

_cleanUp.ForEach(a => a()); 
_cleanUp.Clear(); 
menuStrip1.Items.Clear(); 

然後我不必確切地記得添加了什麼。我可以將任何我喜歡的清理代碼添加到列表中。

相關問題