Overview

BeepDropDownMenu provides an advanced dropdown menu control that extends BeepListBox functionality with smooth animations, intelligent sizing, and integrated dropdown button management. It offers a modern alternative to traditional ComboBox controls with enhanced customization, theming support, and visual appeal.

Built on the BeepListBox foundation, BeepDropDownMenu features animated expand/collapse behavior, intelligent height management, customizable appearance, hit area detection, and comprehensive theme integration. Perfect for selection interfaces, menu systems, filter controls, and any scenario requiring elegant dropdown functionality.

Key Features

?? Smooth Animations

Fluid expand/collapse animations with configurable speed and timing

?? Integrated Button

Built-in dropdown button with automatic icon switching and theme integration

?? Smart Sizing

Intelligent height calculation with maximum height constraints and content adaptation

??? Hit Area Detection

Precise click detection for dropdown button with custom hit area management

?? BeepListBox Heritage

Full BeepListBox functionality including icons, custom items, and selection handling

? Performance Optimized

Efficient animation system with minimal resource usage and smooth operation

Visual Preview

Dropdown States

BeepDropDownMenu showing collapsed and expanded states with smooth transitions

Filter Dropdown Example

Filter interface using multiple BeepDropDownMenu controls for data filtering

Basic Usage

Simple Dropdown Menu

// Create a BeepDropDownMenu
var dropdownMenu = new BeepDropDownMenu();
dropdownMenu.Size = new Size(200, 30);
dropdownMenu.Location = new Point(50, 50);

// Add menu items
dropdownMenu.ListItems.Add(new SimpleItem
{
    Text = "Option 1",
    ImagePath = "option1-icon.svg",
    GuidId = Guid.NewGuid().ToString()
});

dropdownMenu.ListItems.Add(new SimpleItem
{
    Text = "Option 2", 
    ImagePath = "option2-icon.svg",
    GuidId = Guid.NewGuid().ToString()
});

dropdownMenu.ListItems.Add(new SimpleItem
{
    Text = "Option 3",
    ImagePath = "option3-icon.svg",
    GuidId = Guid.NewGuid().ToString()
});

// Handle selection changes
dropdownMenu.SelectedItemChanged += (sender, e) =>
{
    if (dropdownMenu.SelectedItem != null)
    {
      //  Console.WriteLine($"Selected: {dropdownMenu.SelectedItem.Text}");
    }
};

// Add to form
this.Controls.Add(dropdownMenu);

Category Filter Dropdown

public void SetupCategoryFilter()
{
    var categoryFilter = new BeepDropDownMenu
    {
        Size = new Size(180, 30),
        Location = new Point(20, 20),
        Text = "Filter by Category"
    };

    // Add category options
    var categories = new[]
    {
        new { Name = "All Categories", Icon = "all-icon.svg", Value = "" },
        new { Name = "Software Development", Icon = "dev-icon.svg", Value = "software" },
        new { Name = "Design & UI/UX", Icon = "design-icon.svg", Value = "design" },
        new { Name = "Data Science", Icon = "data-icon.svg", Value = "data" },
        new { Name = "Project Management", Icon = "project-icon.svg", Value = "management" },
        new { Name = "Marketing", Icon = "marketing-icon.svg", Value = "marketing" }
    };

    foreach (var category in categories)
    {
        categoryFilter.ListItems.Add(new SimpleItem
        {
            Text = category.Name,
            ImagePath = category.Icon,
            Tag = category.Value,
            GuidId = Guid.NewGuid().ToString()
        });
    }

    // Handle category selection
    categoryFilter.SelectedItemChanged += (sender, e) =>
    {
        if (categoryFilter.SelectedItem != null)
        {
            var selectedCategory = categoryFilter.SelectedItem.Tag?.ToString();
            ApplyCategoryFilter(selectedCategory);
        }
    };

    // Set default selection
    categoryFilter.SelectedIndex = 0;

    this.Controls.Add(categoryFilter);
}

private void ApplyCategoryFilter(string category)
{
    // Apply filter to data grid or list
    if (string.IsNullOrEmpty(category))
    {
        ShowAllItems();
    }
    else
    {
        FilterItemsByCategory(category);
    }
}

Multi-Level Dropdown Configuration

public class DropdownConfiguration
{
    public string Title { get; set; }
    public Size Size { get; set; }
    public Point Location { get; set; }
    public List Items { get; set; } = new List();
    public bool ShowIcons { get; set; } = true;
    public int MaxHeight { get; set; } = 200;
}

public class DropdownItem
{
    public string Text { get; set; }
    public string IconPath { get; set; }
    public object Value { get; set; }
    public bool IsEnabled { get; set; } = true;
}

public BeepDropDownMenu CreateConfiguredDropdown(DropdownConfiguration config)
{
    var dropdown = new BeepDropDownMenu
    {
        Size = config.Size,
        Location = config.Location,
        Text = config.Title
    };

    // Configure maximum height
    if (config.MaxHeight > 0)
    {
        dropdown.MaxMenuHeight = config.MaxHeight;
    }

    // Add items from configuration
    foreach (var item in config.Items)
    {
        var simpleItem = new SimpleItem
        {
            Text = item.Text,
            ImagePath = config.ShowIcons ? item.IconPath : null,
            Tag = item.Value,
            Enabled = item.IsEnabled,
            GuidId = Guid.NewGuid().ToString()
        };

        dropdown.ListItems.Add(simpleItem);
    }

    return dropdown;
}

// Usage example
public void SetupApplicationFilters()
{
    // Priority filter
    var priorityConfig = new DropdownConfiguration
    {
        Title = "Priority",
        Size = new Size(120, 30),
        Location = new Point(20, 60),
        Items = new List
        {
            new DropdownItem { Text = "All", IconPath = "all.svg", Value = null },
            new DropdownItem { Text = "High", IconPath = "high.svg", Value = "high" },
            new DropdownItem { Text = "Medium", IconPath = "medium.svg", Value = "medium" },
            new DropdownItem { Text = "Low", IconPath = "low.svg", Value = "low" }
        }
    };

    var priorityDropdown = CreateConfiguredDropdown(priorityConfig);
    priorityDropdown.SelectedItemChanged += (s, e) => FilterByPriority(priorityDropdown.SelectedItem?.Tag?.ToString());

    // Status filter
    var statusConfig = new DropdownConfiguration
    {
        Title = "Status",
        Size = new Size(140, 30),
        Location = new Point(150, 60),
        Items = new List
        {
            new DropdownItem { Text = "All Statuses", IconPath = "all.svg", Value = null },
            new DropdownItem { Text = "Active", IconPath = "active.svg", Value = "active" },
            new DropdownItem { Text = "Pending", IconPath = "pending.svg", Value = "pending" },
            new DropdownItem { Text = "Completed", IconPath = "completed.svg", Value = "completed" },
            new DropdownItem { Text = "Cancelled", IconPath = "cancelled.svg", Value = "cancelled" }
        }
    };

    var statusDropdown = CreateConfiguredDropdown(statusConfig);
    statusDropdown.SelectedItemChanged += (s, e) => FilterByStatus(statusDropdown.SelectedItem?.Tag?.ToString());

    // Add to form
    this.Controls.Add(priorityDropdown);
    this.Controls.Add(statusDropdown);
}

private void FilterByPriority(string priority) { /* Implementation */ }
private void FilterByStatus(string status) { /* Implementation */ }

Properties

Dropdown-Specific Properties

Property Type Default Description
IsExpanded bool false Whether the dropdown menu is currently expanded
MaxMenuHeight int 200 Maximum height of the dropdown when expanded
CollapsedHeight int 30 Height of the dropdown when collapsed
ButtonWidth int 25 Width of the dropdown button

Animation Properties

Property Type Default Description
AnimationInterval const int 15 Animation timer interval in milliseconds
HeightIncrement const int 10 Height change per animation step
IsAnimating bool false Whether animation is currently in progress

Inherited from BeepListBox

Property Type Description
ListItems BindingList<SimpleItem> Collection of dropdown menu items
SelectedIndex int Index of currently selected item
SelectedItem SimpleItem Currently selected menu item
ShowCheckBox bool Whether to show checkboxes for items

Button Properties

Property Type Description
DropDownButtonGDI BeepButton Internal button used for dropdown rendering

Events

Inherited from BeepListBox

Event Event Args Description
SelectedItemChanged EventHandler Fired when the selected item changes
ListItemClicked Override method Handles individual item clicks from list items

Standard Control Events

Event Description
Click General click events on the control
MouseEnter Mouse entering the control area
MouseLeave Mouse leaving the control area
Resize Control size changes

Examples

Settings Configuration Panel

public class SettingsPanel : Panel
{
    private BeepDropDownMenu themeSelector;
    private BeepDropDownMenu languageSelector;
    private BeepDropDownMenu fontSizeSelector;
    private BeepDropDownMenu layoutSelector;

    public SettingsPanel()
    {
        SetupSettingsControls();
        ApplyLayout();
    }

    private void SetupSettingsControls()
    {
        // Theme selector
        themeSelector = new BeepDropDownMenu
        {
            Size = new Size(150, 30),
            Text = "Select Theme"
        };

        var themes = new[]
        {
            new { Name = "Light Theme", Value = "Light", Icon = "sun.svg" },
            new { Name = "Dark Theme", Value = "Dark", Icon = "moon.svg" },
            new { Name = "Auto (System)", Value = "Auto", Icon = "auto.svg" },
            new { Name = "High Contrast", Value = "HighContrast", Icon = "contrast.svg" }
        };

        foreach (var theme in themes)
        {
            themeSelector.ListItems.Add(new SimpleItem
            {
                Text = theme.Name,
                ImagePath = theme.Icon,
                Tag = theme.Value,
                GuidId = Guid.NewGuid().ToString()
            });
        }

        themeSelector.SelectedItemChanged += (s, e) =>
        {
            if (themeSelector.SelectedItem?.Tag is string selectedTheme)
            {
                ApplyTheme(selectedTheme);
            }
        };

        // Language selector
        languageSelector = new BeepDropDownMenu
        {
            Size = new Size(120, 30),
            Text = "Language"
        };

        var languages = new[]
        {
            new { Name = "English", Code = "en", Flag = "flag-us.svg" },
            new { Name = "Spanish", Code = "es", Flag = "flag-es.svg" },
            new { Name = "French", Code = "fr", Flag = "flag-fr.svg" },
            new { Name = "German", Code = "de", Flag = "flag-de.svg" },
            new { Name = "Chinese", Code = "zh", Flag = "flag-cn.svg" }
        };

        foreach (var lang in languages)
        {
            languageSelector.ListItems.Add(new SimpleItem
            {
                Text = lang.Name,
                ImagePath = lang.Flag,
                Tag = lang.Code,
                GuidId = Guid.NewGuid().ToString()
            });
        }

        languageSelector.SelectedItemChanged += (s, e) =>
        {
            if (languageSelector.SelectedItem?.Tag is string langCode)
            {
                ChangeLanguage(langCode);
            }
        };

        // Font size selector
        fontSizeSelector = new BeepDropDownMenu
        {
            Size = new Size(100, 30),
            Text = "Font Size"
        };

        var fontSizes = new[] { 8, 9, 10, 11, 12, 14, 16, 18, 20, 24 };

        foreach (var size in fontSizes)
        {
            fontSizeSelector.ListItems.Add(new SimpleItem
            {
                Text = $"{size}pt",
                Tag = size,
                GuidId = Guid.NewGuid().ToString()
            });
        }

        fontSizeSelector.SelectedItemChanged += (s, e) =>
        {
            if (fontSizeSelector.SelectedItem?.Tag is int fontSize)
            {
                ChangeFontSize(fontSize);
            }
        };

        // Layout selector
        layoutSelector = new BeepDropDownMenu
        {
            Size = new Size(140, 30),
            Text = "Layout"
        };

        var layouts = new[]
        {
            new { Name = "Standard", Value = "standard", Icon = "layout-standard.svg" },
            new { Name = "Compact", Value = "compact", Icon = "layout-compact.svg" },
            new { Name = "Wide", Value = "wide", Icon = "layout-wide.svg" },
            new { Name = "Sidebar", Value = "sidebar", Icon = "layout-sidebar.svg" }
        };

        foreach (var layout in layouts)
        {
            layoutSelector.ListItems.Add(new SimpleItem
            {
                Text = layout.Name,
                ImagePath = layout.Icon,
                Tag = layout.Value,
                GuidId = Guid.NewGuid().ToString()
            });
        }

        layoutSelector.SelectedItemChanged += (s, e) =>
        {
            if (layoutSelector.SelectedItem?.Tag is string layoutType)
            {
                ChangeLayout(layoutType);
            }
        };

        // Add controls to panel
        this.Controls.AddRange(new Control[] 
        { 
            themeSelector, languageSelector, fontSizeSelector, layoutSelector 
        });
    }

    private void ApplyLayout()
    {
        var startY = 20;
        var spacing = 60;
        var labelOffset = -20;

        // Theme selector
        var themeLabel = new Label { Text = "Theme:", Size = new Size(60, 20), Location = new Point(20, startY + labelOffset) };
        themeSelector.Location = new Point(20, startY);
        this.Controls.Add(themeLabel);

        // Language selector  
        var langLabel = new Label { Text = "Language:", Size = new Size(70, 20), Location = new Point(190, startY + labelOffset) };
        languageSelector.Location = new Point(190, startY);
        this.Controls.Add(langLabel);

        // Font size selector
        var fontLabel = new Label { Text = "Font Size:", Size = new Size(70, 20), Location = new Point(330, startY + labelOffset) };
        fontSizeSelector.Location = new Point(330, startY);
        this.Controls.Add(fontLabel);

        // Layout selector
        var layoutLabel = new Label { Text = "Layout:", Size = new Size(60, 20), Location = new Point(20, startY + spacing + labelOffset) };
        layoutSelector.Location = new Point(20, startY + spacing);
        this.Controls.Add(layoutLabel);
    }

    private void ApplyTheme(string theme)
    {
        // Apply selected theme to application
        Properties.Settings.Default.Theme = theme;
        Properties.Settings.Default.Save();
        
        // Notify application of theme change
        Application.Restart();
    }

    private void ChangeLanguage(string languageCode)
    {
        // Change application language
        Properties.Settings.Default.Language = languageCode;
        Properties.Settings.Default.Save();
        
        // Update UI text
        UpdateUILanguage(languageCode);
    }

    private void ChangeFontSize(int fontSize)
    {
        // Apply font size change
        Properties.Settings.Default.FontSize = fontSize;
        Properties.Settings.Default.Save();
        
        // Update application fonts
        UpdateApplicationFonts(fontSize);
    }

    private void ChangeLayout(string layoutType)
    {
        // Apply layout change
        Properties.Settings.Default.Layout = layoutType;
        Properties.Settings.Default.Save();
        
        // Update application layout
        UpdateApplicationLayout(layoutType);
    }

    // Helper methods
    private void UpdateUILanguage(string languageCode) { /* Implementation */ }
    private void UpdateApplicationFonts(int fontSize) { /* Implementation */ }
    private void UpdateApplicationLayout(string layoutType) { /* Implementation */ }
}

Theming

BeepDropDownMenu inherits comprehensive theming from BeepListBox with additional dropdown-specific styling:

Theme Application

var dropdown = new BeepDropDownMenu
{
    Theme = "DarkTheme",
    Size = new Size(200, 30)
};

// Theme automatically applies to:
// - Dropdown background and borders
// - Item list styling
// - Dropdown button appearance
// - Animation transitions
// - Hover and selection states

// Manual theme refresh
dropdown.ApplyTheme();

Dropdown Theming Properties

  • PanelBackColor - Dropdown background color
  • ButtonBackColor - Dropdown button background
  • ButtonForeColor - Button icon color
  • ButtonHoverBackColor - Button hover state
  • ListBackColor - Item list background
  • ListItemBackColor - Individual item backgrounds
  • ListItemHoverBackColor - Item hover states
  • BorderColor - Control borders and dividers

Best Practices

?? Visual Design

  • Consistent sizing: Use consistent heights for dropdown controls across your application
  • Clear labeling: Provide clear labels or placeholder text for dropdown purpose
  • Icon usage: Use icons consistently to improve visual recognition
  • Animation speed: Keep animations fast enough to feel responsive but smooth

?? Data Management

  • Logical ordering: Order items logically (alphabetical, frequency, importance)
  • Default selection: Set meaningful default selections when appropriate
  • Dynamic updates: Update dropdown contents based on context changes
  • State persistence: Remember user selections where appropriate

? Performance

  • Efficient animation: Use timer-based animations sparingly and efficiently
  • Lazy loading: Load dropdown items only when needed for large datasets
  • Memory management: Dispose of animation timers properly
  • Update optimization: Minimize unnecessary UI updates during animations

?? Implementation

  • Event handling: Handle selection changes appropriately without performance issues
  • Validation: Validate selections and provide feedback for invalid states
  • Accessibility: Support keyboard navigation and screen readers
  • Error handling: Handle edge cases like empty item lists gracefully
?? Animation Tip

Adjust animation speed based on the number of items - shorter lists can animate faster, while longer lists benefit from slightly slower animations for better visual tracking.

? Best Practice

Always provide a meaningful default selection or clear placeholder text to guide users on the dropdown's purpose and expected interaction.

?? Performance Warning

Be mindful of animation timer disposal - ensure timers are properly stopped and disposed to prevent memory leaks in long-running applications.