📋 Overview

BeepListBox is a sophisticated list control that extends the functionality of traditional list boxes with modern features like real-time search, filtering, multi-selection with checkboxes, image support, collapsible mode, and comprehensive theming. Built on the BeepPanel foundation, it provides a professional, customizable solution for data selection scenarios.

The control supports both simple text lists and complex data objects, with automatic layout management, responsive design, and full integration with the Beep theming system. It's designed for enterprise applications requiring robust data selection and presentation capabilities.

🚀 Key Features

🔍 Real-Time Search

Built-in search functionality with instant filtering and placeholder text support

☑️ Multi-Selection

Checkbox-based multi-selection with programmatic access to selected items

🖼️ Image Support

Display images alongside text with configurable sizing and theme integration

📁 Collapsible Mode

Minimize to title-only view to save space in dense UIs

🎨 Advanced Theming

Full theme integration with hover effects, selection states, and custom styling

📱 Responsive Layout

Automatic sizing and layout adjustment based on content and container size

🚀 Basic Usage

Simple List Box

// Create a basic list box
var listBox = new BeepListBox
{
    Size = new Size(200, 250),
    Location = new Point(10, 10),
    TitleText = "Select Items"
};

// Add items
listBox.ListItems.Add(new SimpleItem { Text = "Item 1", Value = "1" });
listBox.ListItems.Add(new SimpleItem { Text = "Item 2", Value = "2" });
listBox.ListItems.Add(new SimpleItem { Text = "Item 3", Value = "3" });

// Handle selection
listBox.ItemClicked += (sender, item) => {
    MessageBox.Show($"Selected: {item.Text}");
};

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

List Box with Search

// Create list box with search functionality
var searchableList = new BeepListBox
{
    Size = new Size(300, 400),
    Location = new Point(10, 10),
    TitleText = "Product Categories",
    
    // Enable search
    ShowSearch = true,
    SearchPlaceholderText = "Search categories...",
    SearchAreaHeight = 30
};

// Add items
var categories = new[]
{
    "Electronics", "Clothing", "Books", "Home & Garden",
    "Sports", "Automotive", "Health", "Beauty",
    "Toys", "Jewelry", "Food", "Office Supplies"
};

foreach (var category in categories)
{
    searchableList.ListItems.Add(new SimpleItem 
    { 
        Text = category, 
        Value = category.ToLower().Replace(" ", "_") 
    });
}

this.Controls.Add(searchableList);

Multi-Selection List Box

// Create list box with checkboxes for multi-selection
var multiSelectList = new BeepListBox
{
    Size = new Size(250, 300),
    Location = new Point(10, 10),
    TitleText = "Select Features",
    
    // Enable checkboxes
    ShowCheckBox = true,
    
    // Visual settings
    MenuItemHeight = 25,
    ShowHilightBox = true
};

// Add feature options
var features = new[]
{
    "Auto-save", "Dark mode", "Notifications", 
    "Sync", "Backup", "Encryption", "Analytics"
};

foreach (var feature in features)
{
    multiSelectList.ListItems.Add(new SimpleItem 
    { 
        Text = feature, 
        Value = feature 
    });
}

// Get selected items
var getSelectedButton = new Button
{
    Text = "Get Selected",
    Location = new Point(270, 10)
};

getSelectedButton.Click += (s, e) => {
    var selected = multiSelectList.SelectedItems;
    var selectedTexts = selected.Select(item => item.Text);
    MessageBox.Show($"Selected: {string.Join(", ", selectedTexts)}");
};

this.Controls.Add(multiSelectList);
this.Controls.Add(getSelectedButton);

Programmatic Selection

// Select by index
listBox.SelectedIndex = 2;

// Select by item text
listBox.SetItemIndex("Item Name");

// Select by item text and value
listBox.SetItemIndex("Item Name", "item_value");

// Select by SimpleItem object
listBox.SelectedItem = specificItem;

// Get current selection
var currentItem = listBox.SelectedItem;
var currentIndex = listBox.SelectedIndex;
💡 Usage Tip

BeepListBox automatically adjusts its layout based on enabled features. Enable ShowSearch for large lists and ShowCheckBox for multi-selection scenarios.

🔍 Search & Filtering

Advanced Search Configuration

// Configure search functionality
var advancedList = new BeepListBox
{
    TitleText = "Employee Directory",
    ShowSearch = true,
    SearchPlaceholderText = "Search by name or department...",
    SearchAreaHeight = 35,
    Size = new Size(350, 400)
};

// Add employee data
var employees = new[]
{
    new { Name = "John Smith", Dept = "Engineering", Email = "john@company.com" },
    new { Name = "Sarah Johnson", Dept = "Marketing", Email = "sarah@company.com" },
    new { Name = "Mike Davis", Dept = "Engineering", Email = "mike@company.com" },
    new { Name = "Lisa Brown", Dept = "Sales", Email = "lisa@company.com" }
};

foreach (var emp in employees)
{
    advancedList.ListItems.Add(new SimpleItem
    {
        Text = emp.Name,
        SubText = emp.Dept, // Secondary text for search
        Value = emp.Email
    });
}

// Programmatic search
public void SearchEmployees(string searchTerm)
{
    advancedList.Search(searchTerm);
}

// Clear search
public void ClearEmployeeSearch()
{
    advancedList.ClearSearch();
}

Custom Filtering Logic

public class FilterableListBox : BeepListBox
{
    private Func _customFilter;
    
    public Func CustomFilter
    {
        get => _customFilter;
        set
        {
            _customFilter = value;
            ApplyCurrentFilter();
        }
    }
    
    public void ApplyCustomFilter(string criteria)
    {
        if (_customFilter == null) return;
        
        // Clear current filtered items
        _filteredOutItems.Clear();
        
        // Apply custom filter logic
        foreach (var item in ListItems)
        {
            if (!_customFilter(item, criteria))
            {
                _filteredOutItems.Add(item);
            }
        }
        
        Invalidate(); // Redraw with filtered items
    }
    
    private void ApplyCurrentFilter()
    {
        if (!string.IsNullOrEmpty(SearchText))
        {
            ApplyCustomFilter(SearchText);
        }
    }
}

// Usage with custom filter
var filterableList = new FilterableListBox
{
    TitleText = "Advanced Search",
    ShowSearch = true
};

// Set up custom filter (search in multiple fields)
filterableList.CustomFilter = (item, searchTerm) =>
{
    var term = searchTerm.ToLowerInvariant();
    return item.Text.ToLowerInvariant().Contains(term) ||
           (item.SubText?.ToLowerInvariant().Contains(term) ?? false) ||
           (item.Value?.ToString().ToLowerInvariant().Contains(term) ?? false);
};

Search with Categories

public void CreateCategorizedSearchList()
{
    var categorizedList = new BeepListBox
    {
        TitleText = "Document Library",
        ShowSearch = true,
        SearchPlaceholderText = "Search documents...",
        Size = new Size(400, 500)
    };
    
    // Add documents with categories
    var documents = new[]
    {
        new { Name = "Project Plan.docx", Category = "Documents", Type = "Word" },
        new { Name = "Budget 2024.xlsx", Category = "Spreadsheets", Type = "Excel" },
        new { Name = "Presentation.pptx", Category = "Presentations", Type = "PowerPoint" },
        new { Name = "Database Backup.sql", Category = "Database", Type = "SQL" },
        new { Name = "User Manual.pdf", Category = "Documents", Type = "PDF" }
    };
    
    foreach (var doc in documents)
    {
        categorizedList.ListItems.Add(new SimpleItem
        {
            Text = doc.Name,
            SubText = $"{doc.Category} - {doc.Type}",
            Value = doc.Name,
            ImagePath = GetDocumentIcon(doc.Type) // Category-based icons
        });
    }
    
    this.Controls.Add(categorizedList);
}

private string GetDocumentIcon(string type)
{
    return type switch
    {
        "Word" => @"Assets\icons\word.svg",
        "Excel" => @"Assets\icons\excel.svg",
        "PowerPoint" => @"Assets\icons\powerpoint.svg",
        "PDF" => @"Assets\icons\pdf.svg",
        "SQL" => @"Assets\icons\database.svg",
        _ => @"Assets\icons\document.svg"
    };
}
✅ Search Features
  • Real-time filtering: Results update as you type
  • Multi-field search: Searches both main text and sub-text
  • Case-insensitive: Search is not case-sensitive
  • Programmatic control: Search and clear methods available

☑️ Selection Modes

Single Selection Mode

// Single selection (default behavior)
var singleSelectList = new BeepListBox
{
    TitleText = "Choose Theme",
    ShowCheckBox = false, // Single selection mode
    Size = new Size(200, 300)
};

// Add theme options
var themes = new[] { "Light", "Dark", "Auto", "High Contrast" };
foreach (var theme in themes)
{
    singleSelectList.ListItems.Add(new SimpleItem { Text = theme, Value = theme });
}

// Handle single selection
singleSelectList.SelectedItemChanged += (sender, e) => {
    if (e.SelectedItem != null)
    {
        ApplyTheme(e.SelectedItem.Value.ToString());
      //  Console.WriteLine($"Theme changed to: {e.SelectedItem.Text}");
    }
};

// Get current selection
public SimpleItem GetCurrentTheme()
{
    return singleSelectList.SelectedItem;
}

// Set selection programmatically
public void SetTheme(string themeName)
{
    singleSelectList.SetItemIndex(themeName);
}

Multi-Selection with Checkboxes

// Multi-selection mode
var multiSelectList = new BeepListBox
{
    TitleText = "Select Permissions",
    ShowCheckBox = true, // Enable multi-selection
    Size = new Size(300, 400)
};

// Add permission options
var permissions = new[]
{
    new { Name = "Read Data", Description = "View information" },
    new { Name = "Write Data", Description = "Create and edit" },
    new { Name = "Delete Data", Description = "Remove information" },
    new { Name = "Admin Access", Description = "Full system access" },
    new { Name = "User Management", Description = "Manage users" },
    new { Name = "System Config", Description = "Change settings" }
};

foreach (var perm in permissions)
{
    multiSelectList.ListItems.Add(new SimpleItem
    {
        Text = perm.Name,
        SubText = perm.Description,
        Value = perm.Name
    });
}

// Handle selection changes (individual items)
multiSelectList.ItemClicked += (sender, item) => {
    UpdatePermissionSummary();
};

// Get all selected items
public List GetSelectedPermissions()
{
    return multiSelectList.SelectedItems
        .Select(item => item.Value.ToString())
        .ToList();
}

// Set specific permissions
public void SetPermissions(List permissionNames)
{
    // Clear current selections
    ClearAllSelections();
    
    // Select specified permissions
    foreach (string permName in permissionNames)
    {
        var item = multiSelectList.ListItems
            .FirstOrDefault(i => i.Value.ToString() == permName);
        if (item != null)
        {
            // Set checkbox state (implementation depends on internal structure)
            SelectItem(item);
        }
    }
}

Selection Management Utilities

public class SelectionManager
{
    private readonly BeepListBox _listBox;
    
    public SelectionManager(BeepListBox listBox)
    {
        _listBox = listBox;
    }
    
    // Select all items (if multi-select enabled)
    public void SelectAll()
    {
        if (!_listBox.ShowCheckBox) return;
        
        foreach (var item in _listBox.ListItems)
        {
            SetItemSelected(item, true);
        }
    }
    
    // Clear all selections
    public void ClearAll()
    {
        if (_listBox.ShowCheckBox)
        {
            foreach (var item in _listBox.ListItems)
            {
                SetItemSelected(item, false);
            }
        }
        else
        {
            _listBox.SelectedIndex = -1;
        }
    }
    
    // Select items by criteria
    public void SelectWhere(Func predicate)
    {
        if (!_listBox.ShowCheckBox) return;
        
        foreach (var item in _listBox.ListItems)
        {
            bool shouldSelect = predicate(item);
            SetItemSelected(item, shouldSelect);
        }
    }
    
    // Get selection statistics
    public SelectionStats GetSelectionStats()
    {
        if (_listBox.ShowCheckBox)
        {
            int total = _listBox.ListItems.Count;
            int selected = _listBox.SelectedItems.Count;
            
            return new SelectionStats
            {
                TotalItems = total,
                SelectedItems = selected,
                SelectionPercentage = total > 0 ? (double)selected / total * 100 : 0
            };
        }
        else
        {
            return new SelectionStats
            {
                TotalItems = _listBox.ListItems.Count,
                SelectedItems = _listBox.SelectedItem != null ? 1 : 0,
                SelectionPercentage = _listBox.SelectedItem != null ? 100 : 0
            };
        }
    }
    
    private void SetItemSelected(SimpleItem item, bool selected)
    {
        // Implementation would depend on internal checkbox structure
        // This is a conceptual example
    }
}

public class SelectionStats
{
    public int TotalItems { get; set; }
    public int SelectedItems { get; set; }
    public double SelectionPercentage { get; set; }
    
    public bool HasSelection => SelectedItems > 0;
    public bool IsFullSelection => SelectedItems == TotalItems && TotalItems > 0;
    public bool IsPartialSelection => SelectedItems > 0 && SelectedItems < TotalItems;
}

🎨 Visual Customization

Image and Icon Configuration

// Configure visual appearance
var visualList = new BeepListBox
{
    TitleText = "File Browser",
    Size = new Size(350, 400),
    
    // Image settings
    ShowImage = true,
    ImageSize = 24,
    ApplyThemeOnImage = true,
    
    // Item settings
    MenuItemHeight = 32,
    ShowHilightBox = true,
    
    // Layout settings
    IsItemChilds = true
};

// Add files with icons
var files = new[]
{
    new { Name = "Document.pdf", Type = "pdf", Size = "2.3 MB" },
    new { Name = "Spreadsheet.xlsx", Type = "excel", Size = "1.8 MB" },
    new { Name = "Image.jpg", Type = "image", Size = "5.4 MB" },
    new { Name = "Archive.zip", Type = "archive", Size = "12.1 MB" }
};

foreach (var file in files)
{
    visualList.ListItems.Add(new SimpleItem
    {
        Text = file.Name,
        SubText = file.Size,
        Value = file.Name,
        ImagePath = GetFileTypeIcon(file.Type)
    });
}

// Font customization
visualList.TextFont = new Font("Segoe UI", 10, FontStyle.Regular);
visualList.UseThemeFont = false; // Use custom font

Custom Styling and Colors

public class StyledListBox : BeepListBox
{
    public StyledListBox()
    {
        InitializeCustomStyling();
    }
    
    private void InitializeCustomStyling()
    {
        // Override default theme colors
        HoverBackColor = Color.FromArgb(240, 248, 255);
        HoverForeColor = Color.FromArgb(0, 100, 200);
        HoverBorderColor = Color.FromArgb(0, 100, 200);
        
        SelectedBackColor = Color.FromArgb(0, 120, 215);
        SelectedForeColor = Color.White;
        SelectedBorderColor = Color.FromArgb(0, 100, 200);
        
        FocusBackColor = Color.FromArgb(230, 245, 255);
        FocusForeColor = Color.FromArgb(0, 100, 200);
        
        // Custom border and radius
        BorderRadius = 8;
        BorderThickness = 2;
        IsRounded = true;
        ShowShadow = true;
    }
    
    public void ApplyCustomColorScheme(ColorScheme scheme)
    {
        switch (scheme)
        {
            case ColorScheme.Professional:
                ApplyProfessionalColors();
                break;
            case ColorScheme.Vibrant:
                ApplyVibrantColors();
                break;
            case ColorScheme.Minimal:
                ApplyMinimalColors();
                break;
        }
        
        ApplyTheme();
        Invalidate();
    }
    
    private void ApplyProfessionalColors()
    {
        BackColor = Color.White;
        ForeColor = Color.FromArgb(33, 37, 41);
        HoverBackColor = Color.FromArgb(248, 249, 250);
        SelectedBackColor = Color.FromArgb(0, 86, 179);
    }
    
    private void ApplyVibrantColors()
    {
        BackColor = Color.FromArgb(255, 255, 255);
        ForeColor = Color.FromArgb(51, 51, 51);
        HoverBackColor = Color.FromArgb(255, 235, 59);
        SelectedBackColor = Color.FromArgb(76, 175, 80);
    }
    
    private void ApplyMinimalColors()
    {
        BackColor = Color.FromArgb(250, 250, 250);
        ForeColor = Color.FromArgb(80, 80, 80);
        HoverBackColor = Color.FromArgb(240, 240, 240);
        SelectedBackColor = Color.FromArgb(120, 120, 120);
    }
}

public enum ColorScheme
{
    Professional,
    Vibrant,
    Minimal
}

Dynamic Sizing and Layout

public class ResponsiveListBox : BeepListBox
{
    public void OptimizeForContent()
    {
        // Auto-size based on content
        int optimalWidth = GetMaxWidth();
        int optimalHeight = GetMaxHeight();
        
        // Apply size with constraints
        Width = Math.Max(200, Math.Min(400, optimalWidth));
        Height = Math.Max(100, Math.Min(600, optimalHeight));
    }
    
    public void SetCompactMode(bool compact)
    {
        if (compact)
        {
            MenuItemHeight = 20;
            ImageSize = 16;
            SearchAreaHeight = 24;
            
            // Reduce padding
            Padding = new Padding(4);
        }
        else
        {
            MenuItemHeight = 28;
            ImageSize = 24;
            SearchAreaHeight = 30;
            
            // Standard padding
            Padding = new Padding(8);
        }
        
        Invalidate();
    }
    
    public void SetDensity(ListDensity density)
    {
        switch (density)
        {
            case ListDensity.Compact:
                MenuItemHeight = 20;
                ImageSize = 16;
                break;
                
            case ListDensity.Standard:
                MenuItemHeight = 28;
                ImageSize = 24;
                break;
                
            case ListDensity.Comfortable:
                MenuItemHeight = 36;
                ImageSize = 32;
                break;
        }
        
        Invalidate();
    }
}

public enum ListDensity
{
    Compact,
    Standard,
    Comfortable
}

📁 Collapsible Mode

Basic Collapsible Functionality

// Create collapsible list box
var collapsibleList = new BeepListBox
{
    TitleText = "Tools Panel",
    Size = new Size(250, 300),
    Location = new Point(10, 10),
    ShowTitle = true
};

// Add items
var tools = new[] { "Calculator", "Notepad", "Color Picker", "Screen Capture" };
foreach (var tool in tools)
{
    collapsibleList.ListItems.Add(new SimpleItem { Text = tool, Value = tool });
}

// Collapse/expand functionality
var toggleButton = new Button
{
    Text = "Toggle",
    Location = new Point(270, 10),
    Size = new Size(80, 30)
};

toggleButton.Click += (s, e) => {
    collapsibleList.Collapsed = !collapsibleList.Collapsed;
    toggleButton.Text = collapsibleList.Collapsed ? "Expand" : "Collapse";
};

this.Controls.Add(collapsibleList);
this.Controls.Add(toggleButton);

Smart Collapsible Layout Manager

public class CollapsibleLayoutManager
{
    private readonly List _managedListBoxes;
    private readonly Dictionary _originalHeights;
    
    public CollapsibleLayoutManager()
    {
        _managedListBoxes = new List();
        _originalHeights = new Dictionary();
    }
    
    public void RegisterListBox(BeepListBox listBox, string groupName = null)
    {
        _managedListBoxes.Add(listBox);
        _originalHeights[listBox] = listBox.Height;
        
        // Add expand/collapse capability to title
        AddToggleToTitle(listBox);
    }
    
    private void AddToggleToTitle(BeepListBox listBox)
    {
        // Add click handler to title area for toggle
        listBox.Click += (s, e) => {
            // Check if click was in title area
            if (IsClickInTitleArea(listBox, e as MouseEventArgs))
            {
                ToggleCollapse(listBox);
            }
        };
    }
    
    public void ToggleCollapse(BeepListBox listBox)
    {
        listBox.Collapsed = !listBox.Collapsed;
        
        // Trigger layout update event
        OnLayoutChanged?.Invoke(new LayoutChangedEventArgs
        {
            ListBox = listBox,
            IsCollapsed = listBox.Collapsed,
            PreviousHeight = _originalHeights[listBox],
            NewHeight = listBox.Height
        });
    }
    
    public void CollapseAll()
    {
        foreach (var listBox in _managedListBoxes)
        {
            if (!listBox.Collapsed)
            {
                listBox.Collapsed = true;
            }
        }
    }
    
    public void ExpandAll()
    {
        foreach (var listBox in _managedListBoxes)
        {
            if (listBox.Collapsed)
            {
                listBox.Collapsed = false;
            }
        }
    }
    
    public void SaveLayout(string layoutName)
    {
        var layout = new LayoutState
        {
            Name = layoutName,
            CollapsedStates = _managedListBoxes.ToDictionary(
                lb => lb.TitleText, 
                lb => lb.Collapsed)
        };
        
        // Save to settings or file
        SaveLayoutState(layout);
    }
    
    public void LoadLayout(string layoutName)
    {
        var layout = LoadLayoutState(layoutName);
        if (layout == null) return;
        
        foreach (var listBox in _managedListBoxes)
        {
            if (layout.CollapsedStates.TryGetValue(listBox.TitleText, out bool collapsed))
            {
                listBox.Collapsed = collapsed;
            }
        }
    }
    
    public event Action OnLayoutChanged;
    
    private bool IsClickInTitleArea(BeepListBox listBox, MouseEventArgs e)
    {
        // Implementation depends on internal title area structure
        return e != null && e.Y <= listBox.TitleBottomY;
    }
}

public class LayoutChangedEventArgs
{
    public BeepListBox ListBox { get; set; }
    public bool IsCollapsed { get; set; }
    public int PreviousHeight { get; set; }
    public int NewHeight { get; set; }
}

public class LayoutState
{
    public string Name { get; set; }
    public Dictionary CollapsedStates { get; set; }
}
📝 Collapsible Mode Benefits
  • Space Efficiency: Maximize screen real estate in dense UIs
  • Organization: Group related functionality that can be hidden when not needed
  • User Control: Let users customize their workspace layout
  • Focus: Reduce visual clutter by hiding secondary options

🔗 Data Binding

Simple Data Binding

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Company { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
}

// Bind list of customers
public void BindCustomers(List customers)
{
    var customerList = new BeepListBox
    {
        TitleText = "Customer List",
        ShowSearch = true,
        SearchPlaceholderText = "Search customers...",
        Size = new Size(400, 500)
    };
    
    // Clear existing items
    customerList.ListItems.Clear();
    
    // Add customers
    foreach (var customer in customers)
    {
        customerList.ListItems.Add(new SimpleItem
        {
            Text = customer.Name,
            SubText = customer.Company,
            Value = customer.Id.ToString(),
            Tag = customer // Store full object
        });
    }
    
    // Handle selection
    customerList.SelectedItemChanged += (s, e) => {
        if (e.SelectedItem?.Tag is Customer selectedCustomer)
        {
            DisplayCustomerDetails(selectedCustomer);
        }
    };
    
    this.Controls.Add(customerList);
}

// Get selected customer
public Customer GetSelectedCustomer(BeepListBox customerList)
{
    return customerList.SelectedItem?.Tag as Customer;
}

Observable Collection Binding

public class DataBoundListBox : BeepListBox
{
    private INotifyCollectionChanged _dataSource;
    
    public IEnumerable DataSource
    {
        get => _dataSource as IEnumerable;
        set
        {
            if (_dataSource != null)
            {
                _dataSource.CollectionChanged -= OnDataSourceChanged;
            }
            
            _dataSource = value as INotifyCollectionChanged;
            
            if (_dataSource != null)
            {
                _dataSource.CollectionChanged += OnDataSourceChanged;
            }
            
            RefreshFromDataSource();
        }
    }
    
    public string DisplayMember { get; set; } = "Text";
    public string ValueMember { get; set; } = "Value";
    public string SubTextMember { get; set; } = "SubText";
    public string ImageMember { get; set; } = "ImagePath";
    
    private void OnDataSourceChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (InvokeRequired)
        {
            Invoke(new Action(() => OnDataSourceChanged(sender, e)));
            return;
        }
        
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                foreach (var item in e.NewItems)
                {
                    AddDataItem(item);
                }
                break;
                
            case NotifyCollectionChangedAction.Remove:
                foreach (var item in e.OldItems)
                {
                    RemoveDataItem(item);
                }
                break;
                
            case NotifyCollectionChangedAction.Reset:
                RefreshFromDataSource();
                break;
        }
    }
    
    private void RefreshFromDataSource()
    {
        ListItems.Clear();
        
        if (DataSource != null)
        {
            foreach (var item in DataSource)
            {
                AddDataItem(item);
            }
        }
    }
    
    private void AddDataItem(object dataItem)
    {
        var listItem = new SimpleItem
        {
            Text = GetPropertyValue(dataItem, DisplayMember)?.ToString() ?? "",
            SubText = GetPropertyValue(dataItem, SubTextMember)?.ToString(),
            Value = GetPropertyValue(dataItem, ValueMember),
            ImagePath = GetPropertyValue(dataItem, ImageMember)?.ToString(),
            Tag = dataItem
        };
        
        ListItems.Add(listItem);
    }
    
    private void RemoveDataItem(object dataItem)
    {
        var listItem = ListItems.FirstOrDefault(item => item.Tag == dataItem);
        if (listItem != null)
        {
            ListItems.Remove(listItem);
        }
    }
    
    private object GetPropertyValue(object obj, string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName) || obj == null)
            return null;
            
        var property = obj.GetType().GetProperty(propertyName);
        return property?.GetValue(obj);
    }
}

// Usage
var observableCustomers = new ObservableCollection();
var dataList = new DataBoundListBox
{
    DataSource = observableCustomers,
    DisplayMember = "Name",
    ValueMember = "Id",
    SubTextMember = "Company",
    TitleText = "Live Customer List"
};

// Add items - they'll automatically appear in the list
observableCustomers.Add(new Customer { Id = 1, Name = "John Doe", Company = "Acme Corp" });

🎨 Theming

Theme Integration

// BeepListBox automatically applies comprehensive theming
public override void ApplyTheme()
{
    base.ApplyTheme();
    
    if (_currentTheme == null) return;
    
    // Apply list-specific theme properties
    BackColor = _currentTheme.ListBackColor;
    ForeColor = _currentTheme.ListForeColor;
    BorderColor = _currentTheme.ListBorderColor;
    
    // Apply hover, selected and disabled states
    HoverBackColor = _currentTheme.ListItemHoverBackColor;
    HoverForeColor = _currentTheme.ListItemHoverForeColor;
    HoverBorderColor = _currentTheme.ListItemHoverBorderColor;
    
    SelectedBackColor = _currentTheme.ListItemSelectedBackColor;
    SelectedForeColor = _currentTheme.ListItemSelectedForeColor;
    SelectedBorderColor = _currentTheme.ListItemSelectedBorderColor;
    
    // Apply fonts based on theme
    if (UseThemeFont)
    {
        if (_currentTheme.ListUnSelectedFont != null)
        {
            TextFont = FontListHelper.CreateFontFromTypography(_currentTheme.ListUnSelectedFont);
        }
        else if (_currentTheme.LabelMedium != null)
        {
            TextFont = BeepThemesManager.ToFont(_currentTheme.LabelMedium);
        }
    }
    
    // Apply search box theming
    if (_searchTextBox != null)
    {
        _searchTextBox.BackColor = _currentTheme.TextBoxBackColor;
        _searchTextBox.ForeColor = _currentTheme.TextBoxForeColor;
        _searchTextBox.BorderStyle = BorderStyle.FixedSingle;
    }
}
🎨 Theming Features
  • Automatic Integration: Inherits all colors from current Beep theme
  • State-Aware: Different colors for hover, selected, focused, and disabled states
  • Typography: Respects theme font settings or allows custom fonts
  • Search Integration: Search box automatically themed to match

⭐ Best Practices

🎨 User Experience

  • Search for Large Lists: Enable search when you have more than 10-15 items
  • Meaningful Item Text: Use clear, descriptive text for list items
  • Consistent Icons: Use a consistent icon style across all items
  • Appropriate Sizing: Choose item heights that balance density with readability

⚡ Performance

  • Efficient Updates: Use batch operations when adding many items
  • Virtual Mode: Consider virtual mode for very large datasets (1000+ items)
  • Search Optimization: Implement efficient search algorithms for large lists
  • Memory Management: Dispose of resources properly, especially with data binding

♿ Accessibility

  • Keyboard Navigation: Ensure full keyboard accessibility
  • Screen Reader Support: Use meaningful text and avoid icon-only items
  • High Contrast: Test with high contrast themes
  • Focus Indicators: Ensure focused items are clearly visible
⚠️ Common Pitfalls
  • Too Many Items: Consider pagination or grouping for lists with 100+ items
  • Poor Search UX: Provide clear feedback when search returns no results
  • Inconsistent Selection: Be clear about single vs multi-selection modes
  • Missing Context: Provide sufficient information for users to make informed selections