BeepComboBox
A themable, painter-driven combo box with 11 visual variants, multi-select, inline editing, search filtering, loading states, and full accessibility support.
Table of Contents
Overview
BeepComboBox is a modern, fully themable combo box control built on the BaseControl framework. It uses a painter methodology where each visual variant (ComboBoxType) delegates rendering to a dedicated painter class, enabling consistent styling across 11 design-system variants while sharing core logic for selection, popup management, and keyboard navigation.
The control is implemented across 6 partial class files and supported by 11 painter classes, 5 helper engines, and the shared BeepContextMenu for dropdown popups. It inherits border rendering, DPI scaling, theme application, and hit-testing from BaseControl.
| Namespace | TheTechIdea.Beep.Winform.Controls |
|---|---|
| Base Class | BaseControl |
| Toolbox Category | Beep Controls |
| Designer Support | Full (ToolboxItem, property grid, design-time painting) |
| Rendering | Painter-driven via IComboBoxPainter with immutable ComboBoxRenderState snapshots |
| Accessibility | Full, via custom AccessibleObject with Value/Role/State overrides |
Key Features
11 Visual Variants
OutlineDefault, OutlineSearchable, FilledSoft, RoundedPill, SegmentedTrigger, MultiChipCompact, MultiChipSearch, DenseList, MinimalBorderless, CommandMenu, VisualDisplay — each with dedicated painter and layout tokens.
Painter Methodology
Stateless frame-by-frame rendering: ComboBoxStateFactory snapshots live state into an immutable ComboBoxRenderState, ComboBoxLayoutEngine computes rectangles, and the active painter renders without reaching back into the control.
Multi-Select with Chips
Two dedicated multi-select variants (MultiChipCompact, MultiChipSearch) render selected items as chip tokens with close (×) buttons, overflow count badges (+N), and animated chip add/remove transitions.
Inline Text Editor
When editable or searchable, a BeepTextBox child control overlays the text area for live typing. Supports auto-complete with prefix/fuzzy/full matching modes, free-text tokenization via delimiter characters, and debounced suggestions.
Searchable Popup
Types that support search (OutlineSearchable, MultiChipSearch, CommandMenu) show a search box in the dropdown. The ComboBoxSearchEngine provides prefix, substring, and fuzzy-subsequence matching against both primary text and sub-text.
Loading States
Two distinct loading mechanisms: an animated spinner that replaces the chevron while IsLoading = true, and a shimmer skeleton sweep when ShowSkeleton = true (for async data population).
Validation States
Four validation states (None, Error, Warning, Success) drive border colour, background tint, and trailing status icons (SVG: AlertCircle, AlertTriangle, Check).
RTL & Accessibility
Full right-to-left layout mirroring via IsRtl. Custom AccessibleObject exposes combo box value, role, and expanded/collapsed state to screen readers. Keyboard navigation covers Up/Down/Home/End/PageUp/PageDown/Enter/Escape/Space/Backspace.
ComboBoxType Variants
The ComboBoxType enum defines 11 design-system variants. Each variant maps to a dedicated IComboBoxPainter implementation and a set of ComboBoxVisualTokens (button width, inner padding, corner radius, text inset, row density). Changing ComboBoxType dynamically swaps the painter and re-applies layout defaults.
| Enum Value | Description | Painter Class | Key Tokens | Search? |
|---|---|---|---|---|
OutlineDefault = 0 | Primary enterprise outlined dropdown with hover/focus accent rings. | OutlineDefaultComboBoxPainter | ButtonW:34, Padding:(12,6,8,6), Radius:6, Separator:Yes | No |
OutlineSearchable = 1 | Outlined dropdown with inline search box in popup and inline editor support. | OutlineSearchableComboBoxPainter | ButtonW:36, Padding:(12,6,8,6), Radius:6, Separator:Yes | Yes |
FilledSoft = 2 | Soft filled field with subtle background tint and modern density. | FilledSoftComboBoxPainter | ButtonW:36, Padding:(12,8,8,8), Radius:8, IsFilled:Yes | No |
RoundedPill = 3 | High-radius pill shell with generous padding. | RoundedPillComboBoxPainter | ButtonW:38, Padding:(16,8,12,8), Radius:18 | No |
SegmentedTrigger = 4 | Split trigger with visually distinct chevron segment using primary colour fill. | SegmentedTriggerComboBoxPainter | ButtonW:40, Padding:(12,6,8,6), Radius:8, Segmented:Yes | No |
MultiChipCompact = 5 | Multi-select chip field with compact token layout; auto-enables AllowMultipleSelection. | MultiChipCompactComboBoxPainter | ButtonW:36, Padding:(10,6,8,6), Radius:8, ChipH:24 | No |
MultiChipSearch = 6 | Multi-select chips with searchable checkbox popup; auto-enables multi-select + search. | MultiChipSearchComboBoxPainter | ButtonW:36, Padding:(10,6,8,6), Radius:8, ChipH:24, Density:36 | Yes |
DenseList = 7 | Data-dense list-oriented variant with compact padding and small button. | DenseListComboBoxPainter | ButtonW:28, Padding:(6,3,4,3), Radius:4, Density:30 | No |
MinimalBorderless = 8 | Low-chrome borderless/minimal shell with smallest button footprint. | MinimalBorderlessComboBoxPainter | ButtonW:22, Padding:(4,6,4,6), Radius:6, Borderless:Yes | No |
CommandMenu = 9 | Command-palette style field with inline search editor and popup rows showing shortcut metadata. | CommandMenuComboBoxPainter | ButtonW:32, Padding:(10,6,8,6), Radius:6, Density:32 | Yes |
VisualDisplay = 10 | Visual-forward display (icon/swatch-first) for selected values with leading image support. | VisualDisplayComboBoxPainter | ButtonW:32, Padding:(10,6,8,6), Radius:8, Separator:Yes | No |
ControlStyle Mapping
When ComboBoxType has not been explicitly set, setting ControlStyle on the control automatically maps to a default ComboBoxType:
Material* → FilledSoft,
iOS15/Apple/PillRail → RoundedPill,
Fluent*/Windows11Mica/Shadcn/RadixUI/NextJS/Linear → OutlineDefault,
Minimal/NotionMinimal/VercelClean → MinimalBorderless,
NeoBrutalist/Brutalist → SegmentedTrigger,
Bootstrap/AntDesign/ChakraUI → OutlineSearchable.
Supporting Enums
BeepAutoCompleteMode
| Value | Description |
|---|---|
None | No auto-complete suggestions. |
Prefix | Matches items starting with the typed text (default). |
Fuzzy | Fuzzy subsequence matching: all typed characters must appear in order in the item text. |
Full | Contains/substring match anywhere in the item text. |
BeepComboBoxValidationState
| Value | Description |
|---|---|
None | No validation state (default). |
Error | Shows red border, error-coloured status icon (AlertCircle), red-tinted background. |
Warning | Shows orange border, warning icon (AlertTriangle), orange-tinted background. |
Success | Shows green border, success check icon (Check), green-tinted background. |
BeepComboBoxSize
| Value | Logical Height | Use Case |
|---|---|---|
Small | 24 px | Compact toolbars, dense forms. |
Medium | 32 px | Default form controls (default). |
Large | 40 px | Prominent inputs, touch-friendly UIs. |
Properties
Data & Selection
| Property | Type | Default | Category | Description |
|---|---|---|---|---|
ListItems | BindingList<SimpleItem> | Empty list | Data | The collection of items in the dropdown. Supports DesignerSerializationVisibility.Content. |
SelectedItem | SimpleItem | null | Data | The currently selected item. Setting resets error state if a valid non-empty item is selected. Fires SelectedItemChanged and SelectedIndexChanged. |
SelectedText | string | "" | Data | Read-only. Returns the text of SelectedItem or the free-typed input text. |
SelectedValue | object | null | Data | Setter accepts SimpleItem or arbitrary values resolved via ResolveItemFromValue. Getter returns item.Value ?? item.Item ?? item.Text. |
SelectedIndex | int | -1 | Data | Index of the selected item. Setting out-of-range clears selection. |
Category | DbFieldCategory | String | Behavior | Database field category for data binding. |
Appearance
| Property | Type | Default | Description |
|---|---|---|---|
ComboBoxType | ComboBoxType | OutlineDefault | Visual variant. Changing swaps the painter, re-applies layout tokens, and may auto-enable multi-select/search. |
ControlStyle | BeepControlStyle | Inherited | Maps to ComboBoxType unless type was explicitly set. |
TextFont | Font | System default | Font for display text. Setting disables theme font. Resolved via BeepThemesManager.ToFont when UseThemeFont = true. |
PlaceholderText | string | "Select an item..." | Placeholder shown when no item is selected and no text has been typed. |
DropdownIconPath | string | "" | Custom path to dropdown icon. Default uses SvgsUI.ChevronDown SVG with animated rotation. |
ShowStatusIcons | bool | false | When true, renders the ImagePath icon for each popup row. |
ShowOptionDescription | bool | true | When true, renders each item's SubText as a second line below the label. |
Behavior
| Property | Type | Default | Description |
|---|---|---|---|
IsEditable | bool | false | Allows text editing via the inline editor. |
ShowSearchInDropdown | bool | false | Forces the search box to appear in the dropdown regardless of type. Auto-enabled for searchable types. |
AutoComplete | bool | true | Enables auto-complete as the user types. |
AutoCompleteMode | BeepAutoCompleteMode | Prefix | Matching strategy: None, Prefix, Fuzzy, or Full. |
AutoCompleteMinLength | int | 1 | Minimum input length before triggering auto-complete. |
MaxSuggestions | int | 10 | Maximum number of auto-complete suggestions. |
AutoCompleteDelay | int | 0 | Debounce delay in milliseconds before triggering auto-complete. |
AnimationDuration | int | 200 | Duration of animations in milliseconds. |
EnableAnimations | bool | true | Whether animations are enabled. |
AnimateChevron | bool | true | Animates chevron rotation (0° closed → 180° open) at ~60 FPS via a 16 ms timer. |
ReduceMotion | bool | false | Skips all timer-driven animations (chevron, spinner, chip) and snaps to final state. |
IsLoading | bool | false | Shows a rotating spinner in the dropdown button area and a translucent haze over text. Disables interaction. |
ShowSkeleton | bool | false | Renders an animated shimmer stripe over the text area. Sweeps left-to-right at ~42 FPS. |
ShowClearButton | bool | false | Shows a × button when a value is selected. Clicking clears selection. |
ValidationState | BeepComboBoxValidationState | None | Drives border colour, status icon, and background tint. |
EmptyStateText | string | "No options" | Text shown when the dropdown list is empty or all items are filtered out. |
AutoFlip | bool | true | When true, the dropdown opens upward if insufficient space below. |
Multi-Select
| Property | Type | Default | Description |
|---|---|---|---|
AllowMultipleSelection | bool | false | Enables multi-select mode. Auto-enabled for MultiChipCompact and MultiChipSearch types. |
SelectedItems | List<SimpleItem> | Empty list | The collection of currently selected items. Setting triggers chip add/remove animations. SelectedItem syncs to first selected item. |
MaxDisplayChips | int | 3 | Number of chips to show before collapsing into a +N overflow badge. |
ChipAnimationDuration | int | 200 | Duration of chip add/remove animations in ms. Animated at ~60 FPS. |
ShowSelectAll | bool | true | Pins a "Select all / Clear all" row at the top of the dropdown in multi-select mode. |
UseApplyCancelFooter | bool | false | Selection changes stay pending until Apply; Cancel restores snapshot. |
UsePrimaryActionFooter | bool | false | Shows a single configurable CTA footer button instead of Apply/Cancel. |
PrimaryActionFooterText | string | "Select {count} item(s)" | Primary CTA footer text. {count} is replaced with selected count. |
AllowFreeText | bool | false | When enabled in multi-select, typing a delimiter converts the current token into a chip. |
TokenDelimiters | char[] | ',', ';' | Characters that trigger free-text tokenization. |
Layout
| Property | Type | Default | Description |
|---|---|---|---|
DropdownButtonWidth | int | 32 | Width of the dropdown button in pixels. ≤0 resets to painter default. |
InnerPadding | Padding | Painter default | Padding inside the combo box. Padding.Empty resets to painter default. |
SizeVariant | BeepComboBoxSize | Medium | Predefined height: Small (24 px), Medium (32 px), Large (40 px). |
MinDropdownWidth | int | 0 | Minimum width of the dropdown. 0 means the popup matches control width. |
DropDownRows | int | 8 | Maximum visible items in the dropdown. Determines popup height. |
AutoSizeDropDown | bool | true | Automatically sizes dropdown width to fit the widest item. |
DropDownWidth | int | 0 | Explicit dropdown width. 0 means auto-size. |
DropdownListBoxType | ListBoxType? | null | ListBoxType for dropdown popup. Null means auto-mapped from ComboBoxType via ComboBoxListBoxTypeMapper. |
MaxDropdownHeight | int | 200 | Maximum height of the dropdown list in pixels. |
IsRtl | bool | false | Mirrors the layout: dropdown button on the left, text right-aligned, chips flow right-to-left. Uses Graphics.ScaleTransform(-1, 1). |
Accessibility
| Property | Type | Default | Description |
|---|---|---|---|
AccessibleName | string | "Combo box" | Name for screen readers. |
AccessibleDescription | string | "Select an item from the dropdown list" | Description for screen readers. |
Methods
Value Access
| Method | Signature | Description |
|---|---|---|
SetValue | void SetValue(object value) | Sets the selected value. Wraps SelectedValue. |
GetValue | object GetValue() | Gets the selected value. Returns SelectedValue. |
ClearSelection | void ClearSelection() | Clears selection, input text, and display text. |
Clear | void Clear() | Clears selection by setting SelectedItem = null. |
Reset | void Reset() | Clears selection, input text, error state, and error text. |
Dropdown Management
| Method | Signature | Description |
|---|---|---|
ShowDropdown | void ShowDropdown() | Opens the dropdown popup. Creates a fresh BeepContextMenu each time. Fires PopupOpened. |
CloseDropdown | void CloseDropdown() | Closes the dropdown popup. Fires PopupClosed. |
ToggleDropdown | void ToggleDropdown() | Toggles the dropdown open/closed state. |
ShowPopup | void ShowPopup() | Legacy alias for ShowDropdown. |
ClosePopup | void ClosePopup() | Legacy alias for CloseDropdown. |
TogglePopup | void TogglePopup() | Legacy alias for ToggleDropdown. |
Editing
| Method | Signature | Description |
|---|---|---|
ShowInlineEditor | void ShowInlineEditor() | Shows the inline BeepTextBox over the text area. Only allowed when editable, free-text, or type supports inline editing. |
HideInlineEditor | void HideInlineEditor(bool commitText) | Hides the inline editor. If true, matches typed text against the list or keeps it as free text. |
StartEditing | void StartEditing() | Delegates to ShowInlineEditor. |
StopEditing | void StopEditing() | Delegates to HideInlineEditor(true). |
Selection Helpers
| Method | Signature | Description |
|---|---|---|
SelectItemByText | void SelectItemByText(string text) | Selects the first item matching by Text (case-insensitive). |
SelectItemByValue | void SelectItemByValue(object value) | Selects by value. Uses ResolveItemFromValue for matching. |
DeselectItem | void DeselectItem(SimpleItem item) | Removes a specific item from the multi-select set. No-op if not selected. |
Layout & Rendering
| Method | Signature | Description |
|---|---|---|
GetTextAreaRect | Rectangle GetTextAreaRect() | Returns the calculated text area rectangle. |
GetDropdownButtonRect | Rectangle GetDropdownButtonRect() | Returns the calculated dropdown button rectangle. |
GetImageRect | Rectangle GetImageRect() | Returns the calculated leading image rectangle. |
Draw | void Draw(Graphics g, Rectangle rect) | Statically paints the combo box into an arbitrary rectangle. Used by grid and container controls. Uses same layout/painter as DrawContent. |
ApplyTheme | override void ApplyTheme() | Applies combo-box-specific theme colours and resolves theme font. |
Events
| Event | Delegate | Raised When |
|---|---|---|
SelectedItemChanged | EventHandler<SelectedItemChangedEventArgs> | The selected item changes (single-select). Fires RaiseSubmitChanges(). |
SelectedIndexChanged | EventHandler<SelectedItemChangedEventArgs> | Raised simultaneously with SelectedItemChanged for backwards compatibility. |
SelectedItemsChanged | EventHandler | The multi-select selection set changes. Fires when items are toggled in the popup. |
PopupOpened | EventHandler | Fires at the end of ShowDropdown after the context menu is displayed. |
PopupClosed | EventHandler | Fires when the dropdown menu closes (via CloseDropdown, MenuClosed, or focus loss). |
The SelectedItemChangedEventArgs carries the newly selected SimpleItem.
Popup Behavior
The dropdown popup is implemented using BeepContextMenu, the same menu infrastructure used by the application menu bar. Each time the dropdown opens:
- A fresh
BeepContextMenuinstance is created withDestroyOnClose = true. - The menu is configured with the combo box's current state:
MultiSelect,ShowCheckBox,ShowSearchBox,Theme. - All
ListItemsare copied toMenuItems, with checkbox state synced for multi-select. - The menu is positioned at
PointToScreen(Point(0, Height))with width matching the control. ItemClickedandMenuClosedevents are wired for selection and state cleanup.
Popup Row Model System
The popup content is normalized through ComboBoxPopupModelBuilder, which converts raw SimpleItem collections into immutable ComboBoxPopupRowModel instances. Each row knows its RowKind:
| RowKind | Description |
|---|---|
Normal | Standard selectable item. |
Selected | Currently selected item (single-select committed value). |
Disabled | Non-interactive, visually muted item. |
GroupHeader | Non-selectable group label. Auto-injected when GroupName changes between items. |
Separator | Thin non-selectable divider line (items with IsSeparator = true). |
WithSubText | Item showing secondary description text below the label. |
CheckRow | Checkbox row for multi-select flows. |
EmptyState | Synthetic row when the list is empty before any search. |
LoadingState | Synthetic row while async data is loading. |
NoResults | Synthetic row when a filter produces zero matches. |
The builder also detects group headers, manages keyboard focus state, and applies ComboBoxSearchEngine filtering. Search results include MatchStart and MatchLength metadata for highlight rendering.
Dropdown ListBoxType Mapping
Each ComboBoxType maps to a ListBoxType for popup appearance. When DropdownListBoxType is null: OutlineDefault → Outlined, FilledSoft → Filled, RoundedPill → Rounded, CommandMenu → CommandList, VisualDisplay → AvatarList, etc.
Inline Editor & Search
Inline Editor Lifecycle
The inline editor is a BeepTextBox child control (frameless, no shadow, ControlStyle.None) created lazily on first use. It overlays _textAreaRect when the user clicks the text area in an editable or searchable combo box.
- Creation: Theme and font applied once at creation — never on every show.
- Show:
ShowInlineEditor()positions the editor over_textAreaRect, pre-fills with current display text, suppresses live-search during programmatic text assignment. - Live Search:
InlineEditor_TextChangedsyncs_inputTextand opens the dropdown if not already open. - Free-Text Tokenization: When
AllowFreeText+AllowMultipleSelectionare enabled, typing,or;creates a chip from the typed token and clears input. - Key Handling: Enter commits, Escape discards, Down commits and shows dropdown.
- Commit:
HideInlineEditor(true)matches typed text viaFindItemByText. If found, selects the match; otherwise keeps free text.
Auto-Complete Engine
Prefix:StartsWith(StringComparison.OrdinalIgnoreCase)Fuzzy: All typed characters must appear in order in the item text (character walk).Full:Contains(StringComparison.OrdinalIgnoreCase)
Configurable debounce via AutoCompleteDelay. Results capped at MaxSuggestions.
Search Engine (Popup)
ComboBoxSearchEngine.FilterRows provides scored search:
- Prefix:
baseWeight + 300 - lengthDiff - Substring:
baseWeight + 200 - startIndex - Fuzzy:
baseWeight + 100 - spread
Group headers are kept only when at least one child item matches. Best match tracked for keyboard focus.
Multi-Select Mode
Enabling
Set AllowMultipleSelection = true or use ComboBoxType.MultiChipCompact / MultiChipSearch. The popup switches to checkbox rows; selected items render as chip tokens.
Chip Layout Engine
ComboBoxChipLayoutEngine computes chip positions left-to-right, wrapping to a second row if needed (up to 2 rows). Each chip has body, text, and close button (16px ×) rectangles. Exceeding space produces a +N overflow badge.
Chip Rendering
ComboBoxChipPainter draws rounded-rect chips using theme tokens (SelectedBackColor, SelectedForeColor, SelectedBorderColor). Disabled chips use muted colours. Contrast ratio checked (2.5:1 minimum). Overflow badge shows +N text centered. Close buttons render SVG X at 75% opacity.
Hit-test rects for chip bodies and close buttons are registered in ChipCloseRects and ChipBodyRects dictionaries, keyed by item identity. Chip body click opens popup and can scroll to item.
Chip Animation
When SelectedItems is set, the setter diffs old/new lists and starts animations for added/removed chips. A 16 ms (~60 FPS) timer drives linear progress 0→1 (add) or 1→0 (remove) over ChipAnimationDuration.
Popup Selection Flow
- Immediate: Checkbox toggle updates
SelectedItemsvia deferredBeginInvoke. Popup stays open. - Apply/Cancel: Pending list; Apply commits, Cancel restores snapshot.
- Primary Action: Single CTA button with
{count}placeholder. - Select All: Virtual
_selectallrow toggles all/none.
Validation & Skeleton Loading
Validation States
ValidationState controls:
- Border: Resolved from
ErrorBorderColor,WarningBorderColor,SuccessBorderColor. - Background tint: 20-alpha overlay over the text area.
- Status icon: Trailing SVG: AlertCircle (error), AlertTriangle (warning), Check (success).
- Text colour: Error state uses
ComboBoxErrorForeColor.
Loading Spinner
When IsLoading = true: translucent haze covers the text area (90-alpha of ComboBoxBackColor). Rotating CircleArrowRight SVG animates in the dropdown button area at 20 FPS (15°/tick, 50 ms). All mouse interaction disabled.
Skeleton Shimmer
When ShowSkeleton = true: all normal content replaced by shimmer. Base gray fill with an animated highlight band sweeping left-to-right using a triangular-blend LinearGradientBrush. Sweep advances at ~42 FPS (24 ms interval, SkeletonOffset 0→1). Clipped to text area.
Theming & Visual Tokens
Theme Token Resolution
ComboBoxStateFactory.Build resolves 40+ colour and font tokens into a ComboBoxThemeTokens snapshot once per paint frame:
| Group | Tokens |
|---|---|
| Field Shell | BackColor, ForeColor, BorderColor, HoverBorderColor, FocusBorderColor, OpenBorderColor |
| Disabled | DisabledBackColor, DisabledForeColor |
| Validation | ErrorBorderColor, WarningBorderColor, SuccessBorderColor, ErrorForeColor |
| Affordances | PlaceholderColor, ChevronColor, ClearButtonColor, SelectionHighlight, ButtonHoverBackground |
| Chip/Selected | SelectedBackColor, SelectedForeColor, SelectedBorderColor |
| Popup Surface | PopupBackColor, PopupBorderColor, PopupRowBack/Hover/Selected/FocusColor, PopupGroupHeaderBack/Fore, PopupMutedForeColor, PopupSeparatorColor, PopupSubTextColor |
| Typography | LabelFont (from LabelFont theme), SubTextFont (from ComboBoxListFont theme) |
A Fallback() method provides sensible Material-style defaults when no theme is active.
Visual Token Catalog
ComboBoxVisualTokenCatalog.Resolve returns layout geometry per type:
| Token | Type | Range | Purpose |
|---|---|---|---|
ButtonWidth | int | 22–40 px | Preferred dropdown button width. |
InnerPadding | Padding | varies | Default padding between border and content. |
CornerRadius | int | 4–18 px | Border corner radius. |
TextInset | int | 6–10 px | Horizontal text inset within text area. |
RowDensity | int | 30–36 px | Popup row height. |
ChipHeight | int | 22–24 px | Chip token height. |
ShowButtonSeparator | bool | — | Vertical separator line between text and button. |
UseSegmentedTrigger | bool | — | Filled, distinct chevron segment. |
IsFilled | bool | — | Filled/tinted text area background. |
ApplyTheme Override
Copies ComboBoxBackColor/ForeColor/BorderColor, hover/selected state colours, syncs inline editor colours from TextBoxBackColor/ForeColor, resolves TextFont via BeepThemesManager.ToFont(ComboBoxItemFont) when UseThemeFont = true. Batched via InvalidateOnce().
Architecture
The BeepComboBox follows a layered architecture with strict separation of concerns:
Partial Class Breakdown
| File | Lines | Contents |
|---|---|---|
BeepComboBox.cs | 57 | Class declaration, attributes (ToolboxItem, DisplayName, Category, Description), accessibility object (BeepComboBoxAccessibleObject). |
BeepComboBox.Core.cs | 743 | Private fields, constructor, layout management, DPI scaling (OnDpiScaleChanged), loading/skeleton timers, chip animation helpers, Dispose. |
BeepComboBox.Properties.cs | 795 | All public properties with [Browsable]/[Category]/[Description]/[DefaultValue] attributes. |
BeepComboBox.Events.cs | 540 | Mouse events, keyboard events (OnKeyDown/KeyPress, ProcessDialogKey), auto-complete logic, fuzzy matching. |
BeepComboBox.Methods.cs | 912 | Public methods (dropdown, inline editor, selection helpers), ApplyTheme, value resolution, popup selection queue, chevron animation trigger, fuzzy search scoring. |
BeepComboBox.Drawing.cs | 240 | DrawContent and Draw overrides, painter factory, hit area registration, loading spinner drawing. |
Render Pipeline (per frame)
DrawContent(g)callsbase.DrawContent(g)(border + background viaBaseControl).ComboBoxStateFactory.Build(this)snapshots all live state into an immutableComboBoxRenderState.ComboBoxLayoutEngine.Compute(DrawingRect, renderState, this)calculates sub-rectangles (text area, dropdown button, clear button, image, chips).- If
IsRtl, all rectangles are mirrored horizontally. - The painter is lazily created via
ComboBoxTypeRegistry.CreatePainter. _comboBoxPainter.Paint(g, this, state, layout)renders chips → text → decorations → clear button → validation icon → dropdown button → spinner/skeleton.RegisterHitAreas()registers interactive zones for mouse hover/cursor changes.
Painter Hierarchy
IComboBoxPainter
├─ ComboBoxFieldPainterBase (background, text, icons, spinner, skeleton, RTL)
├─ DesignSystemComboBoxFieldPainterBase (filled, segmented, borderless, search-icon)
├─ OutlineDefaultComboBoxPainter ─ FilledSoftComboBoxPainter
├─ RoundedPillComboBoxPainter ─ SegmentedTriggerComboBoxPainter
├─ MultiChipCompactComboBoxPainter ─ MultiChipSearchComboBoxPainter
├─ DenseListComboBoxPainter ─ MinimalBorderlessComboBoxPainter
├─ CommandMenuComboBoxPainter ─ VisualDisplayComboBoxPainter
├─ OutlineSearchableComboBoxPainter
Helper Classes
| Class | Location | Purpose |
|---|---|---|
BeepComboBoxHelper | Helpers/ | Text measurement, display text resolution, placeholder detection, item lookup, colour computation. |
ComboBoxTypeRegistry | Helpers/ | Maps ComboBoxType to painter class (factory pattern). |
ComboBoxStateFactory | Helpers/ | Builds immutable ComboBoxRenderState and ComboBoxThemeTokens snapshots. |
ComboBoxLayoutEngine | Helpers/ | Stateless layout calculator producing ComboBoxLayoutSnapshot. |
ComboBoxChipLayoutEngine | Helpers/ | Computes chip positions, wrapping, and overflow badges for multi-select. |
ComboBoxSearchEngine | Helpers/ | Prefix + substring + fuzzy search across popup rows with scoring. |
ComboBoxPopupModelBuilder | Helpers/ | Converts SimpleItem lists into normalized ComboBoxPopupRowModel with group headers, separators, and state flags. |
ComboBoxListBoxTypeMapper | Helpers/ | Maps ComboBoxType to ListBoxType for popup rendering. |
Code Examples
Basic Dropdown
var combo = new BeepComboBox
{
Location = new Point(12, 12),
Size = new Size(240, 32),
ComboBoxType = ComboBoxType.OutlineDefault,
PlaceholderText = "Select a category..."
};
combo.ListItems.Add(new SimpleItem { Text = "Electronics", Name = "Elec" });
combo.ListItems.Add(new SimpleItem { Text = "Books", Name = "Books" });
combo.ListItems.Add(new SimpleItem { Text = "Clothing", Name = "Cloth" });
combo.SelectedItemChanged += (s, e) =>
{
Console.WriteLine($"Selected: {combo.SelectedItem.Text}");
};
this.Controls.Add(combo);
Multi-Select with Chips
var multiCombo = new BeepComboBox
{
ComboBoxType = ComboBoxType.MultiChipSearch,
MaxDisplayChips = 2,
ChipAnimationDuration = 150,
ShowSelectAll = true,
PlaceholderText = "Choose tags..."
};
multiCombo.ListItems.Add(new SimpleItem { Text = "UI/UX", GuidId = "tag1" });
multiCombo.ListItems.Add(new SimpleItem { Text = "Backend", GuidId = "tag2" });
multiCombo.ListItems.Add(new SimpleItem { Text = "DevOps", GuidId = "tag3" });
multiCombo.ListItems.Add(new SimpleItem { Text = "Data Science", GuidId = "tag4" });
multiCombo.ListItems.Add(new SimpleItem { Text = "Security", GuidId = "tag5" });
multiCombo.SelectedItemsChanged += (s, e) =>
{
Console.WriteLine($"Selected {multiCombo.SelectedItems.Count} tag(s)");
};
Searchable with Auto-Complete
var searchCombo = new BeepComboBox
{
ComboBoxType = ComboBoxType.OutlineSearchable,
IsEditable = true,
AutoComplete = true,
AutoCompleteMode = BeepAutoCompleteMode.Fuzzy,
AutoCompleteDelay = 300,
MaxSuggestions = 8,
ShowClearButton = true
};
Command Palette Style
var cmdCombo = new BeepComboBox
{
ComboBoxType = ComboBoxType.CommandMenu,
IsEditable = true
};
cmdCombo.ListItems.Add(new SimpleItem
{
Text = "New File",
SubText = "Create a new document",
ShortcutText = "Ctrl+N"
});
cmdCombo.ListItems.Add(new SimpleItem
{
Text = "Open Folder",
SubText = "Browse and open a directory",
ShortcutText = "Ctrl+O"
});
Validation & Loading
combo.IsLoading = true;
// After data arrives
combo.ListItems = new BindingList<SimpleItem>(fetchedItems);
combo.IsLoading = false;
if (!combo.SelectedItem?.IsEnabled == true)
{
combo.ValidationState = BeepComboBoxValidationState.Error;
}
RTL Support
var rtlCombo = new BeepComboBox
{
IsRtl = true,
ComboBoxType = ComboBoxType.RoundedPill,
PlaceholderText = "اختر عنصرًا..."
};
rtlCombo.ListItems.Add(new SimpleItem { Text = "الخيار الأول" });
rtlCombo.ListItems.Add(new SimpleItem { Text = "الخيار الثاني" });