Overview

The wizard form system provides 4 distinct form types, each backed by a corresponding painter and layout manager. Forms implement IWizardFormHost and use BufferedPanel for flicker-free animation. The architecture follows a strict separation: forms handle structure and layout, painters handle rendering, and layout managers compute control positions.

ConcernComponentRole
Form shellWizardForm (abstract base)Window, navigation buttons, step content area
Step renderingIWizardPainterDraws step indicators, connectors, progress chrome
Layout computationWizardLayoutManagerSizes and positions step indicator area, content panel, nav buttons
AnimationWizardAnimationEngineSlide, fade, flip transitions between steps
Template renderingWizardStepTemplatePre-built step content for Welcome, Config, Progress, Completion

Form Types

Form ClassPainter ClassDescriptionIndicator Style
VerticalStepperWizardFormVerticalStepperPainterLeft sidebar with vertical step indicators. Numbered circles connected by vertical lines. Completed steps show checkmarks. Current step is highlighted with theme accent.Left sidebar, numbered circles (1,2,3...), vertical connector lines
HorizontalStepperWizardFormHorizontalStepperPainterTop horizontal bar with connected step nodes. Filled circles for completed steps, outlined circles with accent for current, gray outlines for upcoming.Top bar, connected nodes, horizontal progress line
MinimalWizardFormMinimalPainterNo visual step indicators. Shows only title bar, content area, and navigation buttons (Back/Next/Cancel). Clean, distraction-free layout for simple flows.None — navigation buttons only
CardsWizardFormCardsPainterCard-based wizard with animated card transitions. Each step renders as a card that flips, slides, or fades into view. Best for onboarding and setup experiences.Card enter/exit animations, flip/slide/fade

All form classes inherit from WizardForm which provides the base window, navigation button bar, and wiring to WizardInstance. The form constructs its painter via WizardPainterFactory and its layout manager via WizardLayoutManagerFactory during initialization.

public abstract class WizardForm : Form
{
    protected IWizardPainter Painter { get; set; }
    protected WizardLayoutManager LayoutManager { get; set; }
    protected BufferedPanel ContentPanel { get; set; }
    protected Button NextButton { get; set; }
    protected Button BackButton { get; set; }
    protected Button CancelButton { get; set; }
    protected Panel NavigationBar { get; set; }

    public abstract void InitializeForm(WizardConfig config);
    public abstract void SetStepContent(Control content);
    public abstract void SetStepTitle(string title);
    public abstract void SetNavigationState(bool canGoBack, bool canGoNext, bool isLastStep);
    public abstract void AnimateTransition(WizardAnimationDirection direction);
}

The WizardFormFactory static class creates the correct form type from WizardStyle:

public static class WizardFormFactory
{
    public static WizardForm CreateForm(WizardStyle style, WizardConfig config)
    {
        return style switch
        {
            WizardStyle.VerticalStepper => new VerticalStepperWizardForm(),
            WizardStyle.HorizontalStepper => new HorizontalStepperWizardForm(),
            WizardStyle.Minimal => new MinimalWizardForm(),
            WizardStyle.Cards => new CardsWizardForm(),
            _ => new VerticalStepperWizardForm()
        };
    }
}

IWizardFormHost Contract

The IWizardFormHost interface defines the contract between the wizard form surface and its client. It exposes methods to set step content, titles, and navigation state, plus events for navigation actions.

public interface IWizardFormHost
{
    void SetStepContent(Control content);
    void SetStepTitle(string title);
    void SetNavigationState(WizardNavigationState state);
    void Close();

    event EventHandler NextClicked;
    event EventHandler BackClicked;
    event EventHandler CancelClicked;
}

WizardNavigationState is a flags enum passed to SetNavigationState:

[Flags]
public enum WizardNavigationState
{
    None = 0,
    CanGoBack = 1,
    CanGoNext = 2,
    IsLastStep = 4,
    IsFirstStep = 8,
    IsBusy = 16,          // Disables all buttons, shows spinner
    HideCancel = 32,
    NextIsFinish = 64     // Changes "Next" button text to "Finish"
}
MemberTypeDescription
SetStepContent(Control)MethodPlaces a control into the wizard content area, replacing any previous content. Triggers the animation engine for the transition.
SetStepTitle(string)MethodUpdates the wizard title bar text. Called at each step transition.
SetNavigationState(WizardNavigationState)MethodControls button visibility, enabled state, and text. Masks CanGoBack, CanGoNext, IsLastStep, IsFirstStep, IsBusy, HideCancel, NextIsFinish.
Close()MethodCloses the wizard form with the appropriate DialogResult.
NextClickedEventFired when user clicks Next/Finish. The subscriber must validate and call NavigateNextAsync() on the WizardInstance.
BackClickedEventFired when user clicks Back. Navigates to the previous step if CanGoBack is true.
CancelClickedEventFired when user clicks Cancel. Sets DialogResult to Cancel and closes the form.

Animation Engine

The WizardAnimationEngine class drives smooth transitions between wizard steps. It uses a BufferedPanel for flicker-free rendering during animation frames. The engine supports three animation types with configurable duration and easing.

public class WizardAnimationEngine
{
    public int DurationMs { get; set; } = 300;
    public WizardAnimationEasing Easing { get; set; } = WizardAnimationEasing.EaseInOutQuad;
    public bool EnableFade { get; set; } = true;

    public async Task AnimateSlideIn(Control control, WizardAnimationDirection direction);
    public async Task AnimateSlideOut(Control control, WizardAnimationDirection direction);
    public async Task AnimateFadeIn(Control control);
    public async Task AnimateFadeOut(Control control);
    public async Task AnimateFlipIn(Control control);
    public async Task AnimateFlipOut(Control control);

    public async Task TransitionContent(BufferedPanel panel, Control oldContent, Control newContent,
        WizardAnimationDirection direction, WizardAnimationType type = WizardAnimationType.Slide);
}
PropertyTypeDefaultDescription
DurationMsint300Animation duration in milliseconds. Range: 100–2000. Lower = snappier, higher = smoother on slow machines.
EasingWizardAnimationEasingEaseInOutQuadEasing curve: Linear, EaseInQuad, EaseOutQuad, EaseInOutQuad, EaseInCubic, EaseOutCubic, EaseInOutCubic, EaseOutBack.
EnableFadebooltrueWhether to apply a cross-fade in addition to the slide/flip effect.

WizardAnimationDirection enum controls slide direction:

public enum WizardAnimationDirection
{
    Forward,   // Slides content from right to left (next step)
    Backward,  // Slides content from left to right (previous step)
    None       // Fade-only, no slide
}

The BufferedPanel is a custom double-buffered panel that eliminates flicker during animation:

public class BufferedPanel : Panel
{
    public BufferedPanel()
    {
        SetStyle(ControlStyles.AllPaintingInWmPaint |
                 ControlStyles.UserPaint |
                 ControlStyles.OptimizedDoubleBuffer |
                 ControlStyles.ResizeRedraw, true);
    }
}

Layout Managers

Each form type delegates its layout computation to a dedicated WizardLayoutManager subclass. Layout managers handle the positioning and sizing of step indicators, content area, and navigation buttons. They respond to form resize events to maintain responsive layouts.

public abstract class WizardLayoutManager
{
    protected WizardForm Form { get; }
    protected Rectangle ContentBounds { get; private set; }
    protected Rectangle IndicatorBounds { get; private set; }
    protected Rectangle NavigationBounds { get; private set; }

    public abstract void PerformLayout();
    public abstract Size GetPreferredSize(Size proposedSize);
    public abstract void InvalidateLayout();
}
Layout ManagerUsed ByLayout Strategy
VerticalStepperLayoutManagerVerticalStepperWizardFormLeft column (280px fixed) for step indicators with vertical number list. Right column for content. Bottom bar for nav buttons. Responds to resize by adjusting content width only.
HorizontalStepperLayoutManagerHorizontalStepperWizardFormTop bar (80px fixed) for horizontal step nodes with connecting lines. Full-width content area below. Bottom bar for nav buttons. Step nodes are evenly distributed across the bar width.
MinimalLayoutManagerMinimalWizardFormNo indicator area. Content fills entire form area above the nav bar. Title is inline above content. Navigation buttons at bottom-right. Simplest layout — max content space.
CardsLayoutManagerCardsWizardFormCentered card region (max 720px wide) with drop shadow and rounded corners. Step dots below the card for position indication. Nav buttons below dots. Card scales down on small windows.

Layout managers expose computed bounds so painters can query exact positioning:

public class VerticalStepperLayoutManager : WizardLayoutManager
{
    public int SidebarWidth { get; } = 280;
    public int StepCircleRadius { get; } = 18;
    public int StepVerticalSpacing { get; } = 56;
    public Point[] StepCircleCenters { get; private set; }

    public override void PerformLayout()
    {
        var steps = Form.Config.Steps.Count;
        IndicatorBounds = new Rectangle(0, 0, SidebarWidth, Form.ClientSize.Height);
        ContentBounds = new Rectangle(SidebarWidth, 80,
            Form.ClientSize.Width - SidebarWidth, Form.ClientSize.Height - 140);
        NavigationBounds = new Rectangle(ContentBounds.X, Form.ClientSize.Height - 60,
            ContentBounds.Width, 60);

        StepCircleCenters = new Point[steps];
        int startY = 100;
        for (int i = 0; i < steps; i++)
            StepCircleCenters[i] = new Point(SidebarWidth / 2, startY + i * StepVerticalSpacing);
    }
}

Step Templates

Wizard step templates provide pre-built, themed step content controls for common wizard scenarios. Each template is a UserControl subclass designed for a specific wizard phase.

TemplateClassPurposeKey Properties
WelcomeWizardStepTemplate.WelcomeLanding/intro step. Large icon/illustration, title, descriptive paragraph, optional "Get Started" call-to-action area.WelcomeTitle, WelcomeMessage, IconImage, ShowFeaturesList, Features
ConfigurationWizardStepTemplate.ConfigurationSettings/config step. Auto-generates labeled input fields from a list of ConfigField objects. Supports text, dropdown, checkbox, file picker.ConfigFields, SectionTitle, ShowAdvancedOptions, ValidationCallback
ProgressWizardStepTemplate.ProgressLong-running operation feedback. Progress bar, status text, cancellation token integration. Updates in real-time via IProgress<T>.ProgressPercent, StatusText, IsIndeterminate, CancelCommand, ShowLog
CompletionWizardStepTemplate.CompletionSummary/success step. Shows a summary of configured options, success/failure indicator, restart or close actions.IsSuccess, SummaryItems, ShowRestartOption, CompletionMessage
var welcomeStep = new WizardStepTemplate.Welcome
{
    WelcomeTitle = "Welcome to Setup",
    WelcomeMessage = "This wizard will guide you through the initial configuration. "
                   + "You can change any setting later.",
    IconImage = Properties.Resources.welcome_icon,
    Features = new List<string> { "Database setup", "Theme selection", "User preferences" }
};

var configStep = new WizardStepTemplate.Configuration
{
    SectionTitle = "Database Configuration",
    ConfigFields = new List<ConfigField>
    {
        new ConfigField { Label = "Server", FieldType = ConfigFieldType.Text, Key = "server" },
        new ConfigField { Label = "Port", FieldType = ConfigFieldType.Text, Key = "port", DefaultValue = "5432" },
        new ConfigField { Label = "Use SSL", FieldType = ConfigFieldType.Checkbox, Key = "useSsl" },
        new ConfigField { Label = "Provider", FieldType = ConfigFieldType.Dropdown, Key = "provider",
            Options = new[] { "PostgreSQL", "SQL Server", "MySQL", "Oracle" } }
    },
    ValidationCallback = (key, value) => ConfigValidator.ValidateField(key, value)
};

var progressStep = new WizardStepTemplate.Progress
{
    ProgressPercent = 0,
    StatusText = "Preparing environment...",
    CancelCommand = new RelayCommand(() => cancellationSource.Cancel())
};

var completionStep = new WizardStepTemplate.Completion
{
    IsSuccess = true,
    CompletionMessage = "Setup completed successfully!",
    SummaryItems = collectedConfig.Select(kvp => new SummaryItem { Label = kvp.Key, Value = kvp.Value }).ToList()
};

Examples

var config = new WizardConfig
{
    Key = "app-setup",
    Title = "Application Setup Wizard",
    Style = WizardStyle.VerticalStepper,
    Steps = new List<WizardStep>
    {
        new WizardStep
        {
            Title = "Welcome",
            Description = "Welcome to the setup wizard",
            Content = welcomeStep
        },
        new WizardStep
        {
            Title = "Database Configuration",
            Description = "Configure your database connection",
            Content = configStep,
            ValidateFn = () => configStep.ValidateFields()
        },
        new WizardStep
        {
            Title = "Installing",
            Description = "Applying your configuration...",
            Content = progressStep,
            SaveFn = () => ApplyConfigurationAsync(configStep.GetValues())
        },
        new WizardStep
        {
            Title = "Complete",
            Description = "Setup is finished",
            Content = completionStep
        }
    },
    ShowCancelButton = true,
    AllowBackNavigation = true
};

var result = WizardManager.ShowWizard(config);

// Custom wizard with validation and async save
var instance = WizardManager.CreateWizard(config);
instance.StepChanging += (s, e) =>
{
    if (e.CurrentStep?.ValidateFn != null && !e.CurrentStep.ValidateFn())
    {
        e.Cancel = true;
        MessageBox.Show("Please correct validation errors before proceeding.");
    }
};
instance.Completed += async (s, e) =>
{
    await SaveWizardResults(instance.Context);
};
instance.ShowDialogAsync();