ContextMenu System
BeepContextMenu architecture -- Form-based modern context menu with 10 partial files, list substrate layout, submenu tracking, WinForms integration, and singleton ContextMenuManager
Table of Contents
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)
| File | Purpose |
|---|---|
| Core.cs | Constructor, ShowAt(Point screenPoint), ShowBelow(Control control), Dismiss sequences, initialization of internal state (items list, style, theme) |
| Properties.cs | Items collection (List<BeepMenuItem>), Style (BeepControlStyle), Theme (string), RoundedCorners (int), ShowIcons (bool), DropShadow (bool), MinimumWidth |
| Methods.cs | Show(ContextMenuStrip compat), ShowAt(Point), ShowBelow(Control), Hide(), AddItem(BeepMenuItem), RemoveItem(int/BeepMenuItem), Clear() |
| Events.cs | ItemClicked (with clicked item and index), Opening (cancelable, before show), Closing (after dismiss started), Closed (after fully hidden) |
| Drawing.cs | OnPaint override: rounded rectangle background, drop shadow (optional), item rendering (hover/selected states, icons, text, shortcut text, submenu arrows, separators) |
| Designer.cs | Design-time item editor (context menu opens in designer for configuration), property visibility control |
| ListSubstrate.cs | List-based layout: calculates item positions (y offset), handles scroll overflow (max menu height, scroll buttons), item height from fonts |
| SubmenuTracking.cs | Nested submenu management: hover-open with delay (open submenu after hover timeout), close on mouse-leave, arrow key navigation between submenus |
| WinFormsIntegration.cs | Compatibility with native ContextMenuStrip patterns: allows assigning BeepContextMenu as ContextMenuStrip of any control, wraps native API |
| KeyboardNavigation.cs | Arrow 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
| Class | Role |
|---|---|
| BeepContextMenuInputHelper | Mouse hit testing: resolves which item is under the cursor. Keyboard input processing. |
| BeepContextMenuLayoutHelper | Item positioning with scroll support. Calculates total height, determines if scrolling is needed, positions scroll indicators. |
| ContextMenuMetrics | Constants: ItemPadding (8,4), ItemHeight (28), IconSize (16), CornerRadius (8), SeparatorHeight (5), MaxMenuHeight (screen 80%), MinMenuWidth (150) |
| BeepContextMenuCloseReason | Enum: ItemClicked (user selected an item), ClickedOutside (user clicked elsewhere), Escape (keyboard dismiss), FocusLost (form deactivated), SubmenuOpened (parent dismissed when submenu opened) |
| MenuDismissedEventArgs | Event 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
ContextMenuStripevents to BeepContextMenu events - Handles Win32 menu messages for interop with native controls
- Allows assigning a BeepContextMenu instance as the
ContextMenuStripproperty of any control:
myControl.ContextMenuStrip = myBeepContextMenu; - Handles the
Control.MouseClickevent to detect right-clicks and show the menu
Menu Lifecycle
- Show trigger -- User right-clicks a control, or code calls
ShowAt(screenPoint)orShowBelow(control) - Opening event --
Openingfires. Applications can modify items or sete.Cancel = trueto prevent display - Display -- Form is positioned, sized to items, and shown with
ShowWithoutActivation - Interaction -- User hovers/clicks items, opens submenus
- Selection -- User clicks an item:
ItemClickedfires,Closingfires,Closedfires, form hides - Dismissal -- User clicks outside, presses Escape, or form loses focus:
Closingfires,Closedfires, 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