【问题标题】:Do I need to explicitly dispose a customized contextmenustrip我是否需要显式处理自定义的上下文菜单条
【发布时间】:2011-11-09 08:00:37
【问题描述】:

我有一个类 clsContextPopUpMenu 来创建一个 ContextMenuStrip,其中包含一些可以在不同控件中使用的基本功能(例如复制)。

    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

例如,我可以在 DataGridView 中使用它DGVTable:

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

但是,请注意m_objPopUpMenu 与具有上述数据网格视图的表单无关。根据MSDN 中的ContextMenuStrip 构造函数解释,我认为m_objPopUpMenu 不能自动处理,因为它不是表单的子项。

我的问题是,我是否必须在设计器中明确处置 m_objPopUpMenu

    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

一个更广泛的问题是,我应该什么时候自己处置对象/资源?当然,gc 收集器并不是释放所有可用内存的魔术师。如上所示,我是否可以始终在 Dispose Sub 中处理对象/资源?

【问题讨论】:

    标签: vb.net contextmenustrip


    【解决方案1】:

    由于对问题的更好理解而修改了答案:

    由于 ContextMenuStrip 实现了 IDisposable,您需要将其添加到表单管理的组件列表中,以便适当地自动处理它,或者按照原始问题中的建议自行管理处理。

    这是您的类的修订版,它将支持自动处置,就像您将 ContextMenuStrip 直接添加到表单中时 Windows 会处理它一样:

    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
    

    从您的表单或用户控件中调用这个新的构造函数:

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

    请注意,我还从构造函数中删除了ByRef,因为它不是必需的,这也消除了在将控件传递给构造函数之前转换控件的需要。

    还有一个注意事项:过去(“过去”)组件不一定出现在每个表单或用户控件上。我相信这已更改/已修复,但如果您发现自己没有,手动添加很容易:

    Private components As System.ComponentModel.IContainer
    

    在你的构造函数中:

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

    在您的 Dispose 方法中(我添加了完整的 dispose 方法以防它不存在;如果存在,则添加与组件​​相关的代码):

    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
    

    【讨论】:

    • 感谢您的回复。我不明白为什么这个实现会因多种形式而变得混乱。 clsContextPopUpMenu 类是一个独立的类。每个表单通过调用 clsContextPopUpMenu 的 New 来启动自己的 clsContextPopUpMenu 对象。但是如何释放每个表单的对象呢? (正如您所提到的,将表单级变量设置为空。您的意思是设置 m_objPopUpMenu=nothing 吗?这与我处理对象的代码不同吗?)
    • 当每个表单实例化 clsContextPopUpMenu 时,您是否将该引用存储在表单内的变量中?如果你这样做,那么你不需要任何额外的代码;标准的 .Net GC 收集过程将处理一切。如果您将引用存储在表单之外(例如,在模块中),那么您需要在表单中添加代码来管理项目的销毁。
    • 在实例化 clsContextPopUpMenu 时,我将引用存储在表单内的变量中。请注意,GC 无法处理非托管资源。我认为上下文菜单条是非托管资源,因为它是图形对象。我的理解错了吗?感谢您的宝贵时间!
    • 好的,既然我更全面地理解了这个问题,我已经用应该回答/解决您问题的完整细节大幅修改了我的答案。
    • 你太棒了!非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多