MyTabPage.vb¶
Two changes in this file¶
- Added a static field
s_CoreModule_ContextMenuFormfor the new singleton popup form. - Modified
ShowContextMenuto dispatch onPageTypeand route core module right-clicks to the new popup, with a defensive rebuild guard.
The original Pulse tab code path is left intact.
Singleton field¶
Private Shared s_PulseTab_ContextMenuForm As FPulseTab_Popup
Private Shared s_CoreModule_ContextMenuForm As FCoreModule_Popup
Private WithEvents m_popAddFilterPopup As New DevExpress.XtraBars.PopupMenu
Private WithEvents m_popContextMenu As DevExpress.XtraBars.PopupMenu
s_CoreModule_ContextMenuForm sits next to s_PulseTab_ContextMenuForm, with the same Private Shared access. Lazy-initialized — the form is constructed on the first right-click that needs it. Once created, it lives for the lifetime of the application.
ShowContextMenu — dispatch by PageType¶
Before:
Public Sub ShowContextMenu(Position As System.Drawing.Point)
If m_popContextMenu Is Nothing Then DefinePopContextMenu()
If m_popContextMenu IsNot Nothing Then
s_PulseTab_ContextMenuForm.Activator = Me
m_popContextMenu.ShowPopup(Position)
End If
End Sub
After:
Public Sub ShowContextMenu(Position As System.Drawing.Point)
' Core module tabs get their own popup; Pulse reporting tabs get
' the original tab popup.
If PageType = ePageType.CORE_MODULE Then
If s_CoreModule_ContextMenuForm Is Nothing Then
s_CoreModule_ContextMenuForm = New FCoreModule_Popup
End If
' Defensive: if the popup has lost its links for any reason
' (e.g. after user switch / settings reload), rebuild them.
If s_CoreModule_ContextMenuForm.PopupMenu1.ItemLinks Is Nothing _
OrElse s_CoreModule_ContextMenuForm.PopupMenu1.ItemLinks.Count = 0 Then
s_CoreModule_ContextMenuForm.DefineContextMenu()
End If
s_CoreModule_ContextMenuForm.Activator = Me
s_CoreModule_ContextMenuForm.PopupMenu1.ShowPopup(Position)
Exit Sub
End If
If m_popContextMenu Is Nothing Then DefinePopContextMenu()
If m_popContextMenu IsNot Nothing Then
s_PulseTab_ContextMenuForm.Activator = Me
s_PulseTab_ContextMenuForm.colorPickEditTabColor.EditValue = Me.TabBackColor
m_popContextMenu.ShowPopup(Position)
End If
End Sub
Branch logic¶
PageType returns:
ePageType.CORE_MODULEwhenm_PrivateCoreModule IsNot Nothing— i.e. the page is a core module tab intcMain.ePageType.PULSE_TAB_PAGEotherwise — a Pulse reporting tab inside an innerMyTabControl.
The branch sends each kind of page to the right popup. Crucially, the Pulse path (the m_popContextMenu block at the bottom) is byte-identical to its original — no behavior changes for Pulse tabs.
The defensive rebuild¶
If s_CoreModule_ContextMenuForm.PopupMenu1.ItemLinks Is Nothing _
OrElse s_CoreModule_ContextMenuForm.PopupMenu1.ItemLinks.Count = 0 Then
s_CoreModule_ContextMenuForm.DefineContextMenu()
End If
In normal flow this branch fires once: on the very first right-click after the form is constructed, ItemLinks.Count = 0 (the designer's LinksPersistInfo is unreliable when item-to-manager registration hasn't completed yet — see Architecture). After DefineContextMenu() runs once, links stay populated and this branch is skipped on every subsequent right-click.
The check is also a safety net: if anything in a future code change ever clears ItemLinks, the next right-click will silently re-populate them rather than presenting an empty menu.
Why pass Position through unchanged¶
The Position parameter comes in as a screen point (the caller in MyTabControl.HandletabMouseClick passes PointToScreen(e.Location)). PopupMenu.ShowPopup(Point) accepts screen coordinates, so we forward as-is. No conversion needed.
What did not change¶
MyTabPage_Click(the body-MouseClick handler) is unchanged. It still callsShowContextMenu(MousePosition). Since core module pages have no body to click on, this path is effectively only used for Pulse tabs and works correctly.DefinePopContextMenu(the Pulse-popup populator) is unchanged.MyTabPage.Disposeis unchanged.- The
New(v_bCreateSplitContainer)constructor that wiresm_popContextMenu = s_PulseTab_ContextMenuForm.PopupMenu1is unchanged. Core module pages use the parameter-lessNew()constructor, which never setm_popContextMenu— and that remains true. PageTypeis unchanged.- Every other handler in
MyTabPage.vbis unchanged.
Risk assessment¶
- Blast radius: Any caller of
ShowContextMenu. There are three: two inMyTabControl.HandletabMouseClickand one inMyTabPage_Click. None pass extra context — they just hand off a screen-spacePoint. The new branch's behavior depends only onPageType, which is a pure read ofm_PrivateCoreModule. - Pulse tab regression risk: Low. The Pulse path is unchanged byte-for-byte after the new dispatch branch.
- Reversibility: Trivial — remove the
If PageType = ePageType.CORE_MODULEblock and thes_CoreModule_ContextMenuFormfield.