Overview

Namespace: TheTechIdea.Beep.Winform.Controls.ContextMenus
Inheritance: System.Windows.Forms.Form (directly, not from any Beep form base)
BeepContextMenu is a modern replacement for the standard ContextMenuStrip. It inherits directly from Form and handles all its own painting using the BeepStyling system, providing rounded corners, drop shadows, icon support, and nested submenus. The class is organized across 10 partial files plus a singleton ContextMenuManager that ensures only one context menu is visible at a time.

Architecture

BeepContextMenu : Form
  +-- Core.cs              -- Constructor, initialization, show/hide sequences
  +-- Properties.cs        -- Items collection, Style, Theme, Font, RoundedCorners, ShowIcons, DropShadow
  +-- Methods.cs           -- ShowAt(point), ShowBelow(control), Dismiss(), AddItem/RemoveItem
  +-- Events.cs            -- ItemClicked, Opening (cancelable), Closing (cancelable), Closed
  +-- Drawing.cs           -- Custom painting: rounded corners, drop shadows, icon + text + shortcut render
  +-- Designer.cs          -- Design-time item editor, property visibility filtering
  +-- ListSubstrate.cs     -- List-based layout engine: item positions, scroll overflow handling
  +-- SubmenuTracking.cs   -- Nested submenu hover-open with delay, close-on-leave, keyboard traversal
  +-- WinFormsIntegration.cs -- Compatibility bridge with native ContextMenuStrip API and Win32 messages
  +-- KeyboardNavigation.cs -- Arrow keys, Enter to select, Escape to close, mnemonics
  + ContextMenuManager.cs  -- Singleton lifecycle manager (separate file, same namespace)

Partial File Layout (10)

FilePurpose
Core.csConstructor, ShowAt(Point screenPoint), ShowBelow(Control control), Dismiss sequences, initialization of internal state (items list, style, theme)
Properties.csItems collection (List<BeepMenuItem>), Style (BeepControlStyle), Theme (string), RoundedCorners (int), ShowIcons (bool), DropShadow (bool), MinimumWidth
Methods.csShow(ContextMenuStrip compat), ShowAt(Point), ShowBelow(Control), Hide(), AddItem(BeepMenuItem), RemoveItem(int/BeepMenuItem), Clear()
Events.csItemClicked (with clicked item and index), Opening (cancelable, before show), Closing (after dismiss started), Closed (after fully hidden)
Drawing.csOnPaint override: rounded rectangle background, drop shadow (optional), item rendering (hover/selected states, icons, text, shortcut text, submenu arrows, separators)
Designer.csDesign-time item editor (context menu opens in designer for configuration), property visibility control
ListSubstrate.csList-based layout: calculates item positions (y offset), handles scroll overflow (max menu height, scroll buttons), item height from fonts
SubmenuTracking.csNested submenu management: hover-open with delay (open submenu after hover timeout), close on mouse-leave, arrow key navigation between submenus
WinFormsIntegration.csCompatibility with native ContextMenuStrip patterns: allows assigning BeepContextMenu as ContextMenuStrip of any control, wraps native API
KeyboardNavigation.csArrow keys up/down to navigate, Enter to select item, Escape to close current level or entire menu, mnemonics (Alt+letter shortcuts)

ContextMenuManager

Singleton in ContextMenuManager.cs. Responsibilities:

  • One menu at a time -- Tracks which context menu is currently visible. Opening a new menu dismisses the previous one.
  • Outside click dismissal -- Hooks into the form's deactivation/mouse-click events to dismiss when the user clicks outside the menu bounds.
  • Focus restoration -- After the menu closes, restores focus to the control that originally opened it.
  • Global tracking -- The manager is a single point of reference for any code that needs to check if a context menu is open.

Helper Classes

ClassRole
BeepContextMenuInputHelperMouse hit testing: resolves which item is under the cursor. Keyboard input processing.
BeepContextMenuLayoutHelperItem positioning with scroll support. Calculates total height, determines if scrolling is needed, positions scroll indicators.
ContextMenuMetricsConstants: ItemPadding (8,4), ItemHeight (28), IconSize (16), CornerRadius (8), SeparatorHeight (5), MaxMenuHeight (screen 80%), MinMenuWidth (150)
BeepContextMenuCloseReasonEnum: ItemClicked (user selected an item), ClickedOutside (user clicked elsewhere), Escape (keyboard dismiss), FocusLost (form deactivated), SubmenuOpened (parent dismissed when submenu opened)
MenuDismissedEventArgsEvent args with CloseReason when the menu is dismissed

WinForms Integration

BeepContextMenu.WinFormsIntegration.cs provides compatibility with the native ContextMenuStrip API pattern:

  • Implements an adapter that bridges ContextMenuStrip events to BeepContextMenu events
  • Handles Win32 menu messages for interop with native controls
  • Allows assigning a BeepContextMenu instance as the ContextMenuStrip property of any control:
    myControl.ContextMenuStrip = myBeepContextMenu;
  • Handles the Control.MouseClick event to detect right-clicks and show the menu

Menu Lifecycle

  1. Show trigger -- User right-clicks a control, or code calls ShowAt(screenPoint) or ShowBelow(control)
  2. Opening event -- Opening fires. Applications can modify items or set e.Cancel = true to prevent display
  3. Display -- Form is positioned, sized to items, and shown with ShowWithoutActivation
  4. Interaction -- User hovers/clicks items, opens submenus
  5. Selection -- User clicks an item: ItemClicked fires, Closing fires, Closed fires, form hides
  6. Dismissal -- User clicks outside, presses Escape, or form loses focus: Closing fires, Closed fires, form hides

Code Examples

var menu = new BeepContextMenu();
menu.Style = BeepControlStyle.Material3;
menu.ShowIcons = true;
menu.RoundedCorners = 8;

menu.Items.Add(new BeepMenuItem("Cut", Icons.Cut, () => Cut()));
menu.Items.Add(new BeepMenuItem("Copy", Icons.Copy, () => Copy()));
menu.Items.Add(new BeepMenuItem("Paste", Icons.Paste, () => Paste()));
menu.Items.Add(new BeepMenuSeparator());
menu.Items.Add(new BeepMenuItem("Delete", Icons.Delete, () => Delete()));

// Show at mouse position
menu.ShowAt(Cursor.Position);

// Show below a control
menu.ShowBelow(myButton);

// Assign as permanent context menu
myTextBox.ContextMenuStrip = menu;  // WinFormsIntegration bridges this