0

ToolStripMenuファイルからエントリを入力していますXML。メニューに追加されたそれぞれToolStripItemは、それに割り当てられた約 12 個のイベント ハンドラーを自動的に取得します。ユーザーには、メニューを変更しXMLて更新するオプションがあり、次を使用してすべてをクリアします。

menuStrip1.Items.Clear();

これにより、フォームから再入力されXML、フォームが更新されます。これらすべての動的アイテムのイベント ハンドラーがメモリから削除されることはないようです。ほとんどの項目は menuStrip1 に直接置かれるのではなく、動的に作成された にあるサブメニューにありますmenuStrip1

それにもかかわらず、私はそこに座ってフォームを更新すると、メモリが制御不能になり、5-10 MB更新ごとに約100 dynamic ToolStripItems. 数百 MB に達し、アプリケーションがクラッシュします。

ToolStripItemsプロパティやアイコンなどの他のものもロードしますが、追加されたメモリのほとんどを使用するのはイベント ハンドラーのようです。すべてのハンドラーをコメントアウトすると、更新のたびにメモリがはるかに (完全ではありませんが) 維持できるようになりました。

すべてのメニューとサブメニューを列挙し、各イベント ハンドラーを個別に解放して、固執しないようにする必要がありますか?

4

3 に答える 3

1

イベント ハンドラーとそれがサブスクライブしているオブジェクトの両方を破棄/削除する場合は、問題ありません。それ以外の場合は、各ハンドラーのサブスクライブを解除する必要があります。

または、コンパイラが生成したイベントではなく、別のサブスクライブ方法を見てください。例については、 http://paulstovell.com/blog/weakeventsを参照してください )

于 2014-02-19T02:31:24.193 に答える
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
    }
}
于 2014-02-19T03:44:47.287 に答える
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();

そうすれば、何が追加されたかを正確に覚える必要はありません。また、好きなクリーンアップ コードをリストに追加できます。

于 2014-02-20T04:51:44.447 に答える