Overview

BeepExtendedButton provides an advanced button control with dual-action functionality, combining primary and secondary action areas within a single button interface. It features split-button behavior, extended menu integration, and sophisticated interaction patterns for complex user interfaces.

Built on the BeepControl foundation, BeepExtendedButton features dual-action zones, customizable button sections, menu item integration, icon management, hover state differentiation, and comprehensive theming support. Perfect for toolbars, command interfaces, split-button scenarios, and applications requiring rich button functionality.

Key Features

🔄 Dual-Action Areas

Separate clickable zones for primary and secondary actions within one button

📋 Menu Integration

Built-in support for menu items and command binding

🎨 Rich Iconography

Support for multiple icons with customizable positioning and sizing

⚡ Split Functionality

Classic split-button behavior with primary action and dropdown options

🎯 Precise Interaction

Distinct hover and click states for different button regions

🔧 Command Binding

Integration with command patterns and menu item hierarchies

Visual Preview

Extended Button Variations and States

Split Button Layout

💾 Save Document
▼
Main: Save with default settings
Extended: Show save options menu

Style Variations

▶️ Run
⚙️
✅ Approve
📋
⚠️ Delete
▼
🔧 Tools
⋮

Interactive States

📤 Export
▼
Normal State
📤 Export
▼
Main Button Hover
📤 Export
▼
Extended Section Hover

With Dropdown Menu

Extended buttons showing dual-action areas, styles, states, and dropdown integration

Basic Usage

Simple Extended Button

// Create and configure a BeepExtendedButton
var extendedButton = new BeepExtendedButton();
extendedButton.Size = new Size(150, 35);
extendedButton.Text = "Save Document";
extendedButton.ButtonImagePath = @"icons\save.png";
extendedButton.ExtendedButtonImagePath = @"icons\arrow-down.png";
extendedButton.RightButtonSize = 25;

// Handle main button click (primary action)
extendedButton.MainButtonClick += (s, e) =>
{
    SaveDocument();
    ShowNotification("Document saved successfully!");
};

// Handle extended button click (secondary actions)
extendedButton.ExtendedButtonClick += (s, e) =>
{
    ShowSaveOptionsMenu(extendedButton);
};

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

Menu Item Integration

// Create extended button with menu item binding
var menuButton = new BeepExtendedButton
{
    Text = "Export Data",
    Size = new Size(120, 32),
    RightButtonSize = 20,
    MenuItem = new MenuItemData 
    { 
        Name = "Export",
        Command = "ExportCommand",
        SubItems = new[]
        {
            new MenuItemData { Name = "Export to Excel", Command = "ExportExcel" },
            new MenuItemData { Name = "Export to PDF", Command = "ExportPDF" },
            new MenuItemData { Name = "Export to CSV", Command = "ExportCSV" }
        }
    }
};

// Set up icons
menuButton.ButtonImagePath = @"icons\export.png";
menuButton.ExtendedButtonImagePath = @"icons\chevron-down.png";

// Handle main action (default export)
menuButton.MainButtonClick += async (s, e) =>
{
    await ExportToDefaultFormat();
};

// Handle extended menu
menuButton.ExtendedButtonClick += (s, e) =>
{
    var contextMenu = CreateExportMenu(menuButton.MenuItem);
    var location = menuButton.PointToScreen(new Point(0, menuButton.Height));
    contextMenu.Show(location);
};

Properties

Core Properties

Property Type Default Description
Text string "" Main button text label
RightButtonSize int 20 Width of the extended button area
MenuItem object null Associated menu item data object

Image Properties

Property Type Default Description
ButtonImagePath string "" Path to main button icon image
ExtendedButtonImagePath string "" Path to extended button icon image
ButtonImage Image null Main button icon image object
ExtendedButtonImage Image null Extended button icon image object

Layout Properties

Property Type Default Description
ImageAlignment ContentAlignment MiddleLeft Alignment of main button image
TextAlignment ContentAlignment MiddleCenter Alignment of button text
ImageTextSpacing int 4 Spacing between image and text

Events

Event Event Args Description
MainButtonClick EventArgs Fired when main button area is clicked
ExtendedButtonClick EventArgs Fired when extended button area is clicked
MainButtonHover EventArgs Fired when mouse enters main button area
ExtendedButtonHover EventArgs Fired when mouse enters extended button area

Examples

Toolbar with Extended Buttons

public partial class ExtendedToolbar : UserControl
{
    private FlowLayoutPanel toolbarPanel;
    private List<BeepExtendedButton> toolbarButtons;

    public ExtendedToolbar()
    {
        InitializeComponents();
        CreateToolbarButtons();
    }

    private void InitializeComponents()
    {
        toolbarPanel = new FlowLayoutPanel
        {
            Dock = DockStyle.Top,
            Height = 45,
            FlowDirection = FlowDirection.LeftToRight,
            WrapContents = false,
            Padding = new Padding(5)
        };

        toolbarButtons = new List<BeepExtendedButton>();
        this.Controls.Add(toolbarPanel);
    }

    private void CreateToolbarButtons()
    {
        var buttonConfigs = new[]
        {
            new { Text = "New", Icon = "new.png", Command = "New", SubCommands = new[] { "Document", "Presentation", "Spreadsheet" } },
            new { Text = "Open", Icon = "open.png", Command = "Open", SubCommands = new[] { "Recent Files", "From Computer", "From Cloud" } },
            new { Text = "Save", Icon = "save.png", Command = "Save", SubCommands = new[] { "Save", "Save As", "Save Copy" } },
            new { Text = "Print", Icon = "print.png", Command = "Print", SubCommands = new[] { "Quick Print", "Print Preview", "Print Setup" } }
        };

        foreach (var config in buttonConfigs)
        {
            var button = CreateExtendedButton(config.Text, config.Icon, config.Command, config.SubCommands);
            toolbarButtons.Add(button);
            toolbarPanel.Controls.Add(button);
        }
    }

    private BeepExtendedButton CreateExtendedButton(string text, string iconPath, string command, string[] subCommands)
    {
        var button = new BeepExtendedButton
        {
            Text = text,
            Size = new Size(90, 35),
            Margin = new Padding(2),
            ButtonImagePath = $@"icons\{iconPath}",
            ExtendedButtonImagePath = @"icons\chevron-down.png",
            RightButtonSize = 18,
            Tag = command
        };

        // Main button click - execute primary command
        button.MainButtonClick += (s, e) =>
        {
            ExecuteCommand(command);
        };

        // Extended button click - show submenu
        button.ExtendedButtonClick += (s, e) =>
        {
            ShowSubCommandMenu(button, subCommands);
        };

        // Visual feedback on hover
        button.MainButtonHover += (s, e) =>
        {
            ShowCommandTooltip(button, $"Execute {command}");
        };

        button.ExtendedButtonHover += (s, e) =>
        {
            ShowCommandTooltip(button, $"More {command} options");
        };

        return button;
    }

    private void ShowSubCommandMenu(BeepExtendedButton button, string[] subCommands)
    {
        var contextMenu = new ContextMenuStrip();
        
        foreach (var subCommand in subCommands)
        {
            var menuItem = new ToolStripMenuItem(subCommand);
            menuItem.Click += (s, e) =>
            {
                ExecuteCommand($"{button.Tag}_{subCommand.Replace(" ", "")}");
            };
            contextMenu.Items.Add(menuItem);
        }

        // Position menu below button
        var location = button.PointToScreen(new Point(0, button.Height));
        contextMenu.Show(location);
    }

    private void ExecuteCommand(string command)
    {
        switch (command)
        {
            case "New":
                CreateNewDocument();
                break;
            case "New_Document":
                CreateNewDocument("Document");
                break;
            case "New_Presentation":
                CreateNewDocument("Presentation");
                break;
            case "Open":
                OpenDocument();
                break;
            case "Open_RecentFiles":
                ShowRecentFiles();
                break;
            case "Save":
                SaveDocument();
                break;
            case "Save_SaveAs":
                SaveDocumentAs();
                break;
            case "Print":
                PrintDocument();
                break;
            case "Print_PrintPreview":
                ShowPrintPreview();
                break;
            default:
                MessageBox.Show($"Command executed: {command}");
                break;
        }
    }

    // Command implementations
    private void CreateNewDocument(string type = "Document") { /* Implementation */ }
    private void OpenDocument() { /* Implementation */ }
    private void ShowRecentFiles() { /* Implementation */ }
    private void SaveDocument() { /* Implementation */ }
    private void SaveDocumentAs() { /* Implementation */ }
    private void PrintDocument() { /* Implementation */ }
    private void ShowPrintPreview() { /* Implementation */ }
    private void ShowCommandTooltip(Control control, string text) { /* Implementation */ }
}

Split Button with Complex Menu

public partial class SplitButtonExample : Form
{
    private BeepExtendedButton exportButton;
    private BeepExtendedButton runButton;

    public SplitButtonExample()
    {
        InitializeComponents();
        SetupSplitButtons();
    }

    private void InitializeComponents()
    {
        this.Size = new Size(400, 300);
        this.Text = "Split Button Example";
    }

    private void SetupSplitButtons()
    {
        // Export split button
        exportButton = new BeepExtendedButton
        {
            Text = "Export Report",
            Size = new Size(150, 40),
            Location = new Point(20, 20),
            ButtonImagePath = @"icons\export.png",
            ExtendedButtonImagePath = @"icons\arrow-down.png",
            RightButtonSize = 25
        };

        exportButton.MainButtonClick += async (s, e) =>
        {
            // Default export action
            await ExportToDefaultFormat();
        };

        exportButton.ExtendedButtonClick += (s, e) =>
        {
            ShowExportMenu();
        };

        // Run split button with recent configurations
        runButton = new BeepExtendedButton
        {
            Text = "Run Configuration",
            Size = new Size(160, 40),
            Location = new Point(20, 80),
            ButtonImagePath = @"icons\run.png",
            ExtendedButtonImagePath = @"icons\history.png",
            RightButtonSize = 30
        };

        runButton.MainButtonClick += async (s, e) =>
        {
            // Run with last configuration
            await RunWithLastConfiguration();
        };

        runButton.ExtendedButtonClick += (s, e) =>
        {
            ShowConfigurationHistory();
        };

        this.Controls.AddRange(new Control[] { exportButton, runButton });
    }

    private void ShowExportMenu()
    {
        var menu = new ContextMenuStrip();

        // Export format options
        var formatMenu = new ToolStripMenuItem("Export Format");
        formatMenu.DropDownItems.Add("Excel (.xlsx)", null, (s, e) => ExportToExcel());
        formatMenu.DropDownItems.Add("PDF Document", null, (s, e) => ExportToPDF());
        formatMenu.DropDownItems.Add("CSV File", null, (s, e) => ExportToCSV());
        formatMenu.DropDownItems.Add("JSON Data", null, (s, e) => ExportToJSON());

        // Export options
        var optionsMenu = new ToolStripMenuItem("Export Options");
        optionsMenu.DropDownItems.Add("Include Headers", null, ToggleIncludeHeaders);
        optionsMenu.DropDownItems.Add("Include Formatting", null, ToggleIncludeFormatting);
        optionsMenu.DropDownItems.Add("Compress Output", null, ToggleCompression);

        // Recent exports
        var recentMenu = new ToolStripMenuItem("Recent Exports");
        var recentExports = GetRecentExports();
        foreach (var export in recentExports)
        {
            recentMenu.DropDownItems.Add($"{export.Name} ({export.Format})", null, 
                (s, e) => RepeatExport(export));
        }

        menu.Items.AddRange(new ToolStripItem[] 
        { 
            formatMenu, 
            optionsMenu, 
            new ToolStripSeparator(),
            recentMenu,
            new ToolStripSeparator(),
            new ToolStripMenuItem("Export Settings...", null, ShowExportSettings)
        });

        var location = exportButton.PointToScreen(new Point(0, exportButton.Height));
        menu.Show(location);
    }

    private void ShowConfigurationHistory()
    {
        var menu = new ContextMenuStrip();

        // Recent configurations
        var configurations = GetRecentConfigurations();
        foreach (var config in configurations)
        {
            var item = new ToolStripMenuItem($"{config.Name}")
            {
                Tag = config,
                Image = GetConfigurationIcon(config.Type)
            };
            item.Click += (s, e) => RunConfiguration(config);
            menu.Items.Add(item);
        }

        if (configurations.Any())
        {
            menu.Items.Add(new ToolStripSeparator());
        }

        // Additional options
        menu.Items.Add("Edit Configurations...", null, ShowConfigurationEditor);
        menu.Items.Add("Save Current as...", null, SaveCurrentConfiguration);
        menu.Items.Add(new ToolStripSeparator());
        menu.Items.Add("Clear History", null, ClearConfigurationHistory);

        var location = runButton.PointToScreen(new Point(0, runButton.Height));
        menu.Show(location);
    }

    // Implementation methods
    private async Task ExportToDefaultFormat() { /* Implementation */ }
    private async Task RunWithLastConfiguration() { /* Implementation */ }
    private void ExportToExcel() { /* Implementation */ }
    private void ExportToPDF() { /* Implementation */ }
    private void ExportToCSV() { /* Implementation */ }
    private void ExportToJSON() { /* Implementation */ }
    private void ToggleIncludeHeaders(object sender, EventArgs e) { /* Implementation */ }
    private void ToggleIncludeFormatting(object sender, EventArgs e) { /* Implementation */ }
    private void ToggleCompression(object sender, EventArgs e) { /* Implementation */ }
    private void RepeatExport(object exportConfig) { /* Implementation */ }
    private void ShowExportSettings(object sender, EventArgs e) { /* Implementation */ }
    private void RunConfiguration(object config) { /* Implementation */ }
    private void ShowConfigurationEditor(object sender, EventArgs e) { /* Implementation */ }
    private void SaveCurrentConfiguration(object sender, EventArgs e) { /* Implementation */ }
    private void ClearConfigurationHistory(object sender, EventArgs e) { /* Implementation */ }
    private IEnumerable<object> GetRecentExports() => new object[0]; // { /* Implementation */ }
    private IEnumerable<object> GetRecentConfigurations() => new object[0]; // { /* Implementation */ }
    private Image GetConfigurationIcon(string type) => null; // { /* Implementation */ }
}

Theming

BeepExtendedButton provides comprehensive theming support with advanced styling for dual-action areas:

Theme Application

var extendedButton = new BeepExtendedButton
{
    Theme = "Professional",
    UseThemeColors = true
};

// Theme automatically applies:
// - MainButtonBackColor: Main button area background
// - ExtendedButtonBackColor: Extended button area background
// - ButtonBorderColor: Border styling for both areas
// - HoverColors: Hover states for each section
// - TextColors: Text and icon colors
// - SeparatorColor: Divider between button areas

Advanced Styling Features

  • Dual-zone theming - Independent styling for main and extended areas
  • State-aware colors - Different colors for normal, hover, and active states
  • Icon integration - Theme-coordinated icon colors and effects
  • Separator styling - Customizable divider between button sections

Best Practices

🎯 User Experience

  • Clear separation: Make it obvious that there are two distinct clickable areas
  • Logical actions: Primary action should be the most common operation
  • Consistent sizing: Maintain proportional sizing between main and extended areas
  • Visual feedback: Provide clear hover states for each clickable zone

🔧 Implementation

  • Event handling: Handle both main and extended button events appropriately
  • Menu positioning: Position dropdown menus to avoid screen edge clipping
  • Icon consistency: Use consistent icon styles and sizing throughout
  • Command patterns: Implement proper command binding for complex operations

♿ Accessibility

  • Keyboard navigation: Support Tab navigation between button areas
  • Screen readers: Provide descriptive labels for both button sections
  • Focus indicators: Clear visual focus indicators for keyboard users
  • Alternative access: Provide alternative ways to access extended functionality
💡 Design Tip

Size the extended button area proportionally - typically 20-30% of the total button width for optimal usability.

✅ Best Practice

Use extended buttons for actions with multiple options, keeping the most common action as the primary button.

⚠️ Usability Warning

Avoid making extended button areas too small (less than 20px width) as they become difficult to target accurately.