Question

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?

Was it helpful?

Solution

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top