0

I have a class clsContextPopUpMenu to create a ContextMenuStrip with some basic functions (e.g.copy) that I can use in different controls.

    Friend Sub New(ByRef objControl As System.Windows.Forms.Control)

    m_objControlContainer = objControl
    m_mnuCopyCell2Clipboard = New ToolStripMenuItem("Copy Cell")
    m_PopupMenu = New ContextMenuStrip
    m_PopupMenu.Items.AddRange(New ToolStripMenuItem() {m_mnuCopyCell2Clipboard})
End Sub

For example, I can use it in a DataGridView DGVTable:

 Private m_objPopUpMenu As clsContextPopUpMenu
 m_objPopUpMenu = New clsContextPopUpMenu(CType(DGVTable, System.Windows.Forms.Control))

However, note that m_objPopUpMenu IS NOT associated with the form having the above datagridview. According to ContextMenuStrip constructor explanation in MSDN, I think that m_objPopUpMenu cannot be disposed automatically since it is not a child of the form.

My question is, do I have to explicitly dispose m_objPopUpMenu in designer:

    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    Try
        If disposing AndAlso components IsNot Nothing Then
            components.Dispose()
            **m_objPopUpMenu.Dispose()**
        End If
    Finally
        MyBase.Dispose(disposing)
    End Try
End Sub

A broader question is that when should I dispose objects/resource by myself? Of course, gc collector is not a magician to release all available memory. Can I always dispose objects/resource in Dispose Sub as shown above?

competent_tech
  • 44,465
  • 11
  • 90
  • 113
Summer
  • 241
  • 2
  • 10
  • 23

1 Answers1

1

Revised answer due to better understanding of issue:

Because the ContextMenuStrip implements IDisposable, you will either need to add it to the list of Components managed by the form so that it is disposed appropriately and automatically or manage the disposal yourself as suggested in your original question.

Here is a revision of your class that will support the automatic disposal in the same way that windows would handle it if you were to add ContextMenuStrip directly to the form:

Friend Sub New(ByVal objControl As System.Windows.Forms.Control, ByVal components As System.ComponentModel.IContainer)

    m_objControlContainer = objControl
    m_mnuCopyCell2Clipboard = New ToolStripMenuItem("Copy Cell")
    m_PopupMenu = New ContextMenuStrip(components)
    m_PopupMenu.Items.AddRange(New ToolStripMenuItem() {m_mnuCopyCell2Clipboard})
End Sub

To call this new constructor from within your form or user control:

 Private m_objPopUpMenu As clsContextPopUpMenu
 m_objPopUpMenu = New clsContextPopUpMenu(DGVTable, Me.components)

Note that I also removed the ByRef from the constructor since it is not required, which also eliminates the need to cast the controls before passing them to the constructor.

One additional note: it used to be ("back in the day") that components was not necessarily present on every form or user control. I believe that this has changed/been fixed, but if you find yourself without, it is easy to add manually:

Private components As System.ComponentModel.IContainer

In your constructor:

Me.components = New System.ComponentModel.Container()

In your Dispose method (I have added the full dispose method in case it is not already present; if it is, just added the components-related code):

Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing Then
        If Not (components Is Nothing) Then
            components.Dispose()
        End If
    End If
    MyBase.Dispose(disposing)
End Sub
competent_tech
  • 44,465
  • 11
  • 90
  • 113
  • Thanks for youre reply. I do not understand why this implementation gets messy with multiple forms. Class clsContextPopUpMenu is an independent class. Each form initiates its own object of clsContextPopUpMenu by calling New of clsContextPopUpMenu. But how to release the object for each form? (As you mentioned, set the form-level variable to nothing. Do you mean set m_objPopUpMenu=nothing? Is this different from my code that dispose object?) – Summer Nov 08 '11 at 15:05
  • When each form instantiates the clsContextPopUpMenu, do you store that reference in a variable within the form? If you do this, then you don't need to have any additional code; the standard .Net GC collection process will take care of everything. If you are storing the reference outside of the form (say in a Module, for example), then you would need to add code to your form to manage the destruction of the item. – competent_tech Nov 08 '11 at 19:03
  • I store reference in a variable within the form when instantiating clsContextPopUpMenu. Note that GC cannot take care of unmanaged resource. I thought context menu strip is unmanaged resource since it is graphics object. My understanding is wrong? Thanks for your time! – Summer Nov 08 '11 at 21:29
  • Ok, now that I understand the issue more fully, I have substantially revised my answer with full details that should answer/resolve your question. – competent_tech Nov 09 '11 at 00:02