SalDropDownList
Overview
A custom Windows Forms drop-down list control built around the standard System.Windows.Forms.ComboBox. It provides a more customizable control surface while retaining the underlying ComboBox functionality for items, data binding, selection, searching, and drop-down behavior.
The control combines an internal ComboBox with a custom-drawn Button, allowing the visible control face, border, arrow, placeholder state, text alignment, colors, and drop-down item rendering to be customized independently. It also supports purpose-specific rendering for fonts and country lists, including font-specific text rendering and country flag images.
Technologies Used
- Language: C#
- Framework / UI:
- .NET Framework 4.8
- Windows Forms
System.Drawingfor custom rendering
- Project Components:
Salem.Drawing— drawing-related helpers and country flag resourcesSalem.Utils— utility functionality including localized predefined item collections
- Project Configuration:
- Traditional MSBuild
.csprojproject targeting .NET Framework 4.8 - Release XML documentation generation
- Traditional MSBuild
Features and Functionality
ComboBox-Compatible Data and Selection
-
The control exposes the main functionality of its internal
ComboBox, includingItems,DataSource,DisplayMember,ValueMember,SelectedIndex,SelectedItem,Sorted,Text,DropDownWidth,DropDownHeight,MaxDropDownItems,FormattingEnabled,FormatString,andFormatInfo. -
It also exposes searching through
FindStringandFindStringExact, item-height retrieval, display-text retrieval, andBeginUpdate/EndUpdatefor controlling updates while modifying the item collection.
Custom Control Appearance
SalDropDownListadds appearance properties that are not provided in this form by the standard ComboBox:- Custom border color and thickness
- Custom drop-down arrow color
- Mouse-over and mouse-down background colors
- Placeholder text and placeholder text color
- Control-face text alignment
- Control-face text padding
- Custom drop-down item alignment
- Configurable drop-down item height
- The visible button is custom painted to draw the border and a chevron-style drop-down arrow using the
Segoe Fluent Iconsfont.
Placeholder Behavior
-
When no item is selected, the control displays configurable placeholder text such as
"Select"and uses a separate placeholder text color. -
When an item becomes selected, the button instead displays the selected item’s text and switches back to the control’s foreground color.
Purpose-Specific Item Collections
- The base class provides a
Purposeproperty with predefined modes for:- Installed fonts
- Countries
- Paper sizes
- Months
- Days of the week
- Changing the purpose populates the underlying item collection using the corresponding helper methods. This occurs only at runtime giving you the freedom to change the
Purposeproperty at design-time without actually populating theItemscollection. This allows for better designer experience as the items specified at design-time aren’t overriden immediately upon settingPurpose. This also makes the auto-generated code for the control shorter without cluttering it with item insertions and creating dedicated localized strings when working on a localized UI.
Specialized Item Rendering
-
The control uses
OwnerDrawVariablemode for the internal ComboBox. -
For the
Fontspurpose, each item can be rendered using aFontconstructed from the item’s name, allowing the font’s name to be displayed using the font itself. -
For the
Countriespurpose, each item can be rendered with a country flag image alongside its text. The image and text rectangles are calculated separately so that the layout can be adjusted for left-to-right and right-to-left interfaces.
Right-to-Left Support
-
The drawing logic accounts for
RightToLeftchanges when determining text alignment, country flag placement, text placement relative to the flag, drop-down arrow placement, and button layout. -
The base class changes its drawing delegates when the
RightToLeftproperty changes rather than using a single fixed layout.
Events
-
The custom control exposes events corresponding to important ComboBox operations, including
DropDown,DropDownClosed,SelectedIndexChanged,SelectionChangeCommitted, andTextUpdate. -
These events are forwarded from the internal ComboBox through virtual event-raiser methods in the base class.
Technical Implementation
Composite Control Architecture
-
Rather than deriving
SalDropDownListdirectly fromComboBox, the implementation derives it from an abstractSalDropDownBase, which itself derives fromControl. - The base class owns two internal controls:
- A
ComboBoxresponsible for the actual list, selection, data binding, and drop-down functionality. - A
Buttonresponsible for the visible control face and custom interaction/rendering.
- A
-
SalDropDownListconfigures the internal ComboBox withComboBoxStyle.DropDownListand makes the button the primary visible interaction surface. Clicking the button focuses the ComboBox and opens its drop-down. - This separates the standard ComboBox functionality from the custom visual representation.
Shared Base-Class Functionality
SalDropDownBasecontains functionality common to the drop-down control family, including:- ComboBox property forwarding
- Event forwarding
- Owner-drawn item rendering
- Variable item-height handling
- Purpose-specific item population
- Right-to-left layout handling
- Font-dependent dimension calculation
- Resource cleanup
- The class is abstract and defines several abstract hooks such as
AdjustDimensions,InnerButton_Paint, and handlers for internal ComboBox events. This allows derived controls to provide their own control-face behavior while reusing the common drop-down implementation.
Owner-Drawn Variable-Height Items
-
The internal ComboBox is initialized with
DrawMode = OwnerDrawVariable, and the control implements bothDrawItemandMeasureItem. -
MeasureItemobtains the active item height through a delegate. The implementation caches the normal ComboBox item height by temporarily switching to normal drawing mode, then restores owner-drawn mode. - This provides two item-height modes:
-1: use the ComboBox’s calculated default item height.- A non-negative value: use the explicitly configured height.
- Changing the configured height forces the ComboBox to transition between normal and owner-drawn modes so that measurement is recalculated.
Purpose-Aware Rendering
-
Rendering is selected according to the current
Purpose. General items are drawn directly withGraphics.DrawString. Font items can instead construct aSystem.Drawing.Fontusing the item’s text as the font family name. Country items can retrieve a corresponding flag image and render it beside the item text. -
The implementation therefore keeps the general rendering path simple while adding specialized paths only for purposes that require additional visual information.
Custom Control-Face Rendering
-
The button is not used merely as a standard button. Its
Paintevent is used to draw the visual representation of the drop-down control. -
The paint routine calculates the arrow and optional country-image regions, draws the configured border, optionally draws the selected country’s flag, and finally renders a chevron character using the
Segoe Fluent Iconsfont. -
This allows the button to act as the customizable visual shell around the underlying ComboBox.
Dimension Management
-
The control recalculates its height from the internal ComboBox’s
PreferredHeight. It also recalculates the cached image size used by the country-flag rendering. -
Dimension adjustment occurs when the control is created, resized, and when its font changes. This keeps the custom control face synchronized with the dimensions expected by the underlying ComboBox.
Design-Time Integration
-
The public properties contain Windows Forms design-time metadata such as
Category,Description,DefaultValue,Localizable,Browsable,Bindable, andDesignerSerializationVisibility. -
Several ComboBox-related properties also reuse Windows Forms designer editors and converters for data members, item collections, and format strings.
-
This allows the custom control to expose much of the familiar ComboBox configuration model through the Windows Forms designer rather than forcing all configuration to occur programmatically.
Resource and Event Cleanup
- Both the base class and
SalDropDownListoverrideDispose. The base class disposes its internal Button and ComboBox as well as theSolidBrushandStringFormatinstances used during drawing.SalDropDownListalso explicitly unsubscribes its event handlers before disposal.
Summary
SalDropDownList is a composite WinForms control that extends the standard ComboBox model rather than replacing it. Its implementation separates the underlying list and data-binding behavior from a custom-painted control face, while an abstract base class centralizes common drop-down functionality such as owner-drawn rendering, variable item heights, purpose-specific item population, RTL layout, and event forwarding.
The most distinctive parts of the implementation are its owner-drawn font and country-list modes, custom control-face rendering, and the mechanism used to retain the ComboBox’s default item sizing while supporting variable-height custom rendering.
How to Use
- Compile the source code into a DLL and add that as reference in your project.