What are Beep Widgets?

Beep Widgets are self-contained, paint-based WinForms controls that deliver rich visual output without child controls. Each widget:

  • Inherits from BaseControl — full theme support, Border, Padding, and Hover states come for free.
  • Has a Style enum property that switches the entire visual rendering mode (e.g. MetricWidgetStyle.GaugeMetric).
  • Uses an IWidgetPainter / WidgetContext pipeline — background, content, and foreground accents are drawn in three separate passes.
  • Fires strongly-typed BeepEventDataArgs events for every meaningful user interaction.
  • Re-applies the currently active BeepTheme automatically when the application theme changes.
Namespace: TheTechIdea.Beep.Winform.Controls.Widgets
Base class: BaseControl (→ Control)
Toolbox category: Beep Widgets

Architecture

The widget rendering pipeline consists of three layers:

// IWidgetPainter interface
void Initialize(BaseControl owner, IBeepTheme theme);
WidgetContext AdjustLayout(Rectangle drawingRect, WidgetContext ctx);
void DrawBackground(Graphics g, WidgetContext ctx);
void DrawContent(Graphics g, WidgetContext ctx);
void DrawForegroundAccents(Graphics g, WidgetContext ctx);
void UpdateHitAreas(BaseControl owner, WidgetContext ctx, Action<string, Rectangle> notifyAreaHit);

The WidgetContext object carries all layout rectangles, colours, and data needed for a single paint pass. The widget control populates the context from its properties; the current painter reads it.

Painter Selection

When the Style property changes, the widget calls InitializePainter() which instantiates the matching concrete painter class and calls Initialize() followed by Invalidate().

// Example: changing a metric widget style at runtime
metricWidget.Style = MetricWidgetStyle.GaugeMetric;
// The widget automatically swaps in GaugeMetricPainter and repaints.

Quick Start

// 1. Drop any widget on a form, or create programmatically:
var metric = new BeepMetricWidget
{
    Style      = MetricWidgetStyle.ValueWithTrend,
    Title      = "Monthly Revenue",
    Value      = "$127,450",
    TrendValue = "+8.3%",
    ShowTrend  = true,
    Size       = new Size(220, 120)
};
panel.Controls.Add(metric);

// 2. Handle events:
metric.ValueClicked += (s, e) => ShowRevenueDetail();

// 3. Theme changes are picked up automatically via ApplyTheme().

Using a Chart Widget

var chart = new BeepChartWidget
{
    Style      = ChartWidgetStyle.LineChart,
    Title      = "Sales Trend",
    Values     = new List<double> { 120, 135, 98, 160, 175, 210 },
    Labels     = new List<string> { "Jan","Feb","Mar","Apr","May","Jun" },
    ShowLegend = true
};
chart.DataPointClicked += (s, e) => Console.WriteLine(e.Data);

Available Widgets (13)

Best Practices

  • Set Size before adding to a container — each widget has a sensible default size but you should adjust it to fit your layout.
  • Use Style enums, not magic numbers — always assign the strongly-typed enum value.
  • Avoid overlapping widgets — widgets are GDI+ paint-based and do not clip to parent containers automatically.
  • Let the theme engine drive colours — avoid hard-coding color properties; most colour properties default to the current theme values.
  • Reuse widget instances — updating data properties and calling Invalidate() is cheaper than creating a new widget.
  • Handle BeepEventDataArgs.Data — the Data property contains context-specific clicked-item data (index, value, label, etc.).