State Services
SharpConsoleUI includes built-in state management services for managing different aspects of the UI. These services are automatically created and available through the ConsoleWindowSystem instance.
Table of Contents
- Overview
- WindowStateService
- FocusStateService
- ModalStateService
- NotificationStateService
- ThemeStateService
- CursorStateService
- InputStateService
- PluginStateService
Overview
All state services are accessible through the ConsoleWindowSystem instance:
var windowSystem = new ConsoleWindowSystem(new NetConsoleDriver(RenderMode.Buffer));
// Access state services
windowSystem.WindowStateService
windowSystem.FocusStateService
windowSystem.ModalStateService
windowSystem.NotificationStateService
windowSystem.ThemeStateService
windowSystem.CursorStateService
windowSystem.InputStateService
windowSystem.PluginStateService
WindowStateService
Manages window registration, z-order, and window lifecycle.
Key Properties
// Get all registered windows
IReadOnlyDictionary<string, Window> Windows { get; }
// Get the currently active (focused) window
Window? ActiveWindow { get; }
// Check if in drag or resize operation
bool IsDragging { get; }
bool IsResizing { get; }
Key Methods
// Register a window
void RegisterWindow(Window window);
// Unregister a window
void UnregisterWindow(string windowId);
// Bring window to front (update z-order)
void BringToFront(Window window);
// Get windows in z-order (top to bottom)
IEnumerable<Window> GetWindowsInZOrder();
// Start drag operation
void StartDrag(Window window, Point startMousePos);
// Start resize operation
void StartResize(Window window, Point startMousePos, ResizeDirection direction);
// End drag/resize operations
void EndDrag();
void EndResize();
Usage Example
// Get all windows sorted by z-order
var windows = windowSystem.WindowStateService.GetWindowsInZOrder();
foreach (var window in windows)
{
Console.WriteLine($"Window: {window.Title} (Z: {window.ZOrder})");
}
// Check active window
var active = windowSystem.WindowStateService.ActiveWindow;
if (active != null)
{
Console.WriteLine($"Active window: {active.Title}");
}
// Check if user is dragging a window
if (windowSystem.WindowStateService.IsDragging)
{
Console.WriteLine("Window drag in progress");
}
FocusStateService
Manages keyboard focus tracking for windows and controls.
Key Properties
// Currently focused window
Window? FocusedWindow { get; }
// Currently focused control within the focused window
IWindowControl? FocusedControl { get; }
Key Methods
// Set focus to a window
void SetFocusedWindow(Window? window);
// Set focus to a control
void SetFocusedControl(IWindowControl? control);
// Get window that contains a control
Window? GetWindowForControl(IWindowControl control);
Events
// Fired when focused window changes
event EventHandler<FocusChangedEventArgs>? FocusedWindowChanged;
// Fired when focused control changes
event EventHandler<FocusChangedEventArgs>? FocusedControlChanged;
Usage Example
// Subscribe to focus changes
windowSystem.FocusStateService.FocusedWindowChanged += (sender, e) =>
{
Console.WriteLine($"Focus changed to: {e.CurrentWindow?.Title ?? "none"}");
};
// Set focus programmatically
windowSystem.FocusStateService.SetFocusedWindow(myWindow);
// Get current focus
var focusedWindow = windowSystem.FocusStateService.FocusedWindow;
var focusedControl = windowSystem.FocusStateService.FocusedControl;
ModalStateService
Manages modal window stack and blocking behavior.
Key Properties
// Check if there are any modal windows
bool HasModals { get; }
// Get the topmost modal window
Window? TopModal { get; }
// Get count of modal windows
int ModalCount { get; }
Key Methods
// Push a window onto the modal stack
void PushModal(Window window);
// Remove a window from the modal stack
void RemoveModal(Window window);
// Check if a window is modal
bool IsModal(Window window);
// Check if a window should be blocked (beneath a modal)
bool IsBlockedByModal(Window window);
Usage Example
// Create a modal dialog
var dialog = new WindowBuilder(windowSystem)
.WithTitle("Confirmation")
.WithSize(40, 10)
.Centered()
.AsModal() // This calls PushModal internally
.Build();
windowSystem.AddWindow(dialog);
// Check modal state
if (windowSystem.ModalStateService.HasModals)
{
var topModal = windowSystem.ModalStateService.TopModal;
Console.WriteLine($"Modal active: {topModal?.Title}");
}
// Check if a window is blocked
bool isBlocked = windowSystem.ModalStateService.IsBlockedByModal(mainWindow);
NotificationStateService
Manages notification display, timeout, and dismissal.
Key Properties
// Get current notification state
NotificationState State { get; }
// Check if there are active notifications
bool HasNotifications => State.HasNotifications;
// Get count of active notifications
int ActiveCount => State.ActiveCount;
Notification Severity
public enum NotificationSeverity
{
None, // Gray
Info, // Blue
Success, // Green
Warning, // Yellow
Danger // Red
}
Key Methods
// Show a notification
string ShowNotification(
string title,
string message,
NotificationSeverity severity,
bool blockUi = false,
int? timeout = 5000,
Window? parentWindow = null
);
// Dismiss a notification by ID
bool DismissNotification(string notificationId);
// Dismiss all notifications
void DismissAllNotifications();
// Get notification by ID
NotificationInfo? GetNotification(string notificationId);
Events
// Fired when a notification is shown
event EventHandler<NotificationEventArgs>? NotificationShown;
// Fired when a notification is dismissed
event EventHandler<NotificationEventArgs>? NotificationDismissed;
Usage Examples
// Show a simple notification (auto-dismisses after 5 seconds)
windowSystem.NotificationStateService.ShowNotification(
title: "File Saved",
message: "Your document has been saved successfully",
severity: NotificationSeverity.Success
);
// Show a blocking notification (user must dismiss)
windowSystem.NotificationStateService.ShowNotification(
title: "Error",
message: "Failed to connect to database",
severity: NotificationSeverity.Danger,
blockUi: true,
timeout: null // No auto-dismiss
);
// Show notification with custom timeout
windowSystem.NotificationStateService.ShowNotification(
title: "Processing",
message: "Operation in progress...",
severity: NotificationSeverity.Info,
timeout: 10000 // 10 seconds
);
// Show notification attached to a specific window
windowSystem.NotificationStateService.ShowNotification(
title: "Validation Error",
message: "Please fill in all required fields",
severity: NotificationSeverity.Warning,
parentWindow: formWindow
);
// Subscribe to notification events
windowSystem.NotificationStateService.NotificationShown += (sender, e) =>
{
Console.WriteLine($"Notification shown: {e.Notification.Title}");
};
windowSystem.NotificationStateService.NotificationDismissed += (sender, e) =>
{
Console.WriteLine($"Notification dismissed: {e.Notification.Title}");
};
// Dismiss specific notification
string notificationId = windowSystem.NotificationStateService.ShowNotification(
"Info", "Message", NotificationSeverity.Info);
// Later...
windowSystem.NotificationStateService.DismissNotification(notificationId);
// Dismiss all notifications
windowSystem.NotificationStateService.DismissAllNotifications();
ThemeStateService
Manages current theme and theme transitions.
Key Properties
// Get current active theme
ITheme CurrentTheme { get; }
Key Methods
// Set the active theme
void SetTheme(ITheme theme);
// Get the current theme
ITheme GetCurrentTheme();
Events
// Fired when theme changes
event EventHandler<ThemeChangedEventArgs>? ThemeChanged;
Usage Example
// Subscribe to theme changes
windowSystem.ThemeStateService.ThemeChanged += (sender, e) =>
{
Console.WriteLine($"Theme changed from {e.OldTheme} to {e.NewTheme}");
// Refresh custom UI elements
UpdateCustomColors();
};
// Get current theme
var currentTheme = windowSystem.ThemeStateService.CurrentTheme;
Console.WriteLine($"Current theme window background: {currentTheme.WindowBackgroundColor}");
// Set theme programmatically
windowSystem.ThemeStateService.SetTheme(new ModernGrayTheme());
CursorStateService
Manages console cursor visibility and position.
Key Properties
// Check if cursor is currently visible
bool IsCursorVisible { get; }
// Get current cursor position
Point CursorPosition { get; }
Key Methods
// Show/hide cursor
void ShowCursor();
void HideCursor();
// Set cursor position
void SetCursorPosition(int x, int y);
void SetCursorPosition(Point position);
// Save and restore cursor position
void SaveCursorPosition();
void RestoreCursorPosition();
Usage Example
// Hide cursor during rendering
windowSystem.CursorStateService.HideCursor();
// Show cursor for input
windowSystem.CursorStateService.ShowCursor();
windowSystem.CursorStateService.SetCursorPosition(10, 5);
// Save and restore cursor position
windowSystem.CursorStateService.SaveCursorPosition();
// ... do something ...
windowSystem.CursorStateService.RestoreCursorPosition();
InputStateService
Manages input state and key/mouse event processing.
Key Properties
// Check if a key is currently pressed
bool IsKeyPressed(ConsoleKey key);
// Get mouse button states
bool IsLeftButtonPressed { get; }
bool IsRightButtonPressed { get; }
bool IsMiddleButtonPressed { get; }
// Get current mouse position
Point MousePosition { get; }
Key Methods
// Track key press/release
void SetKeyPressed(ConsoleKey key, bool isPressed);
// Track mouse button press/release
void SetMouseButtonPressed(MouseButton button, bool isPressed);
// Update mouse position
void UpdateMousePosition(Point position);
// Reset all input state
void Reset();
Usage Example
// Check if a key is being held down
if (windowSystem.InputStateService.IsKeyPressed(ConsoleKey.LeftControl))
{
Console.WriteLine("Ctrl key is pressed");
}
// Check mouse button state
if (windowSystem.InputStateService.IsLeftButtonPressed)
{
var mousePos = windowSystem.InputStateService.MousePosition;
Console.WriteLine($"Left mouse button is down at ({mousePos.X}, {mousePos.Y})");
}
// Reset input state (useful when losing focus)
windowSystem.InputStateService.Reset();
PluginStateService
Manages the plugin system, including plugin loading, service registration, control/window factories, and plugin state tracking.
Key Properties
// Get current plugin system state
PluginState CurrentState { get; }
// Get loaded plugins
IReadOnlyList<IPlugin> LoadedPlugins { get; }
// Get registered plugin contributions
IReadOnlyCollection<string> RegisteredControlNames { get; }
IReadOnlyCollection<string> RegisteredWindowNames { get; }
IReadOnlyCollection<string> RegisteredServiceNames { get; }
IReadOnlyCollection<IPluginService> RegisteredServices { get; }
// Get configuration
PluginConfiguration Configuration { get; }
PluginState Record
public record PluginState(
int LoadedPluginCount,
int RegisteredServiceCount,
int RegisteredControlCount,
int RegisteredWindowCount,
IReadOnlyList<string> PluginNames,
bool AutoLoadEnabled,
string? PluginsDirectory
);
Key Methods
// Load plugins
void LoadPlugin<T>() where T : IPlugin, new();
void LoadPlugin(IPlugin plugin);
void LoadPlugin(string dllPath);
void LoadPluginsFromDirectory(string? pluginsPath = null);
// Query plugins
IPlugin? GetPlugin(string name);
bool IsPluginLoaded(string name);
// Create plugin content
IWindowControl? CreateControl(string name);
Window? CreateWindow(string name);
// Access plugin services
IPluginService? GetService(string serviceName);
bool HasService(string serviceName);
T? GetService<T>() where T : class; // Legacy, deprecated
// Configuration
void UpdateConfiguration(PluginConfiguration configuration);
Events
// Fired when plugin state changes
event EventHandler<PluginStateChangedEventArgs>? StateChanged;
// Fired when a plugin is loaded
event EventHandler<PluginEventArgs>? PluginLoaded;
// Fired when a plugin is unloaded
event EventHandler<PluginEventArgs>? PluginUnloaded;
// Fired when a service is registered
event EventHandler<ServiceRegisteredEventArgs>? ServiceRegistered;
Usage Example
// Load a plugin
windowSystem.PluginStateService.LoadPlugin<DeveloperToolsPlugin>();
// Get current state
var state = windowSystem.PluginStateService.CurrentState;
Console.WriteLine($"Loaded plugins: {state.LoadedPluginCount}");
Console.WriteLine($"Registered services: {state.RegisteredServiceCount}");
Console.WriteLine($"Registered controls: {state.RegisteredControlCount}");
// Subscribe to plugin events
windowSystem.PluginStateService.PluginLoaded += (sender, e) =>
{
Console.WriteLine($"Plugin loaded: {e.Info.Name} v{e.Info.Version}");
windowSystem.NotificationStateService.ShowNotification(
"Plugin Loaded",
$"{e.Info.Name} is now available",
NotificationSeverity.Success
);
};
windowSystem.PluginStateService.StateChanged += (sender, e) =>
{
Console.WriteLine($"Plugin count: {e.PreviousState.LoadedPluginCount} → {e.NewState.LoadedPluginCount}");
};
// Check if a plugin is loaded
if (windowSystem.PluginStateService.IsPluginLoaded("DeveloperTools"))
{
Console.WriteLine("DeveloperTools plugin is available");
}
// Get a plugin by name
var devTools = windowSystem.PluginStateService.GetPlugin("DeveloperTools");
if (devTools != null)
{
Console.WriteLine($"Found plugin: {devTools.Info.Description}");
}
// Create plugin control
var logExporter = windowSystem.PluginStateService.CreateControl("LogExporter");
if (logExporter != null)
{
mainWindow.AddControl(logExporter);
}
// Create plugin window
var debugWindow = windowSystem.PluginStateService.CreateWindow("DebugConsole");
if (debugWindow != null)
{
windowSystem.AddWindow(debugWindow);
}
// Access plugin service
var diagnostics = windowSystem.PluginStateService.GetService("Diagnostics");
if (diagnostics != null)
{
var report = (string)diagnostics.Execute("GetDiagnosticsReport")!;
Console.WriteLine(report);
}
// Get all registered service names
var services = windowSystem.PluginStateService.RegisteredServiceNames;
Console.WriteLine($"Available services: {string.Join(", ", services)}");
// Auto-load plugins from directory with configuration
var pluginConfig = new PluginConfiguration(
AutoLoad: true,
PluginsDirectory: "./plugins"
);
var windowSystem = new ConsoleWindowSystem(
new NetConsoleDriver(RenderMode.Buffer),
pluginConfiguration: pluginConfig
);
// Plugins are loaded automatically on startup
Complete Example
Here's an example using multiple state services together:
using SharpConsoleUI;
using SharpConsoleUI.Builders;
using SharpConsoleUI.Controls;
using SharpConsoleUI.Core;
using SharpConsoleUI.Drivers;
var windowSystem = new ConsoleWindowSystem(new NetConsoleDriver(RenderMode.Buffer));
// Create main window
var mainWindow = new WindowBuilder(windowSystem)
.WithTitle("State Services Demo")
.WithSize(80, 25)
.Centered()
.Build();
// Subscribe to focus changes
windowSystem.FocusStateService.FocusedWindowChanged += (sender, e) =>
{
windowSystem.NotificationStateService.ShowNotification(
"Focus Changed",
$"Window: {e.CurrentWindow?.Title ?? "None"}",
NotificationSeverity.Info,
timeout: 2000
);
};
// Subscribe to theme changes
windowSystem.ThemeStateService.ThemeChanged += (sender, e) =>
{
windowSystem.NotificationStateService.ShowNotification(
"Theme Changed",
"UI appearance has been updated",
NotificationSeverity.Success,
timeout: 2000
);
};
// Add buttons to test services
mainWindow.AddControl(
Controls.Button("Show Info")
.OnClick((sender, e, window) =>
{
var windows = windowSystem.WindowStateService.Windows;
var hasModals = windowSystem.ModalStateService.HasModals;
var focusedWindow = windowSystem.FocusStateService.FocusedWindow;
windowSystem.NotificationStateService.ShowNotification(
"System Info",
$"Windows: {windows.Count}, Modals: {hasModals}, Focused: {focusedWindow?.Title}",
NotificationSeverity.Info
);
})
.Build()
);
mainWindow.AddControl(
Controls.Button("Change Theme")
.OnClick((sender, e, window) =>
{
windowSystem.ShowThemeSelectorDialog();
})
.Build()
);
mainWindow.AddControl(
Controls.Button("Show Modal")
.OnClick((sender, e, window) =>
{
var dialog = new WindowBuilder(windowSystem)
.WithTitle("Modal Dialog")
.WithSize(40, 10)
.Centered()
.AsModal()
.Build();
dialog.AddControl(new MarkupControl(new List<string>
{
"[yellow]This is a modal dialog[/]",
"",
"Press ESC to close"
}));
dialog.KeyPressed += (s, ev) =>
{
if (ev.KeyInfo.Key == ConsoleKey.Escape)
{
windowSystem.CloseWindow(dialog);
ev.Handled = true;
}
};
windowSystem.AddWindow(dialog);
})
.Build()
);
windowSystem.AddWindow(mainWindow);
windowSystem.Run();
Best Practices
- Don't modify state directly: Always use service methods to change state
- Subscribe to events: Use state change events to react to system changes
- Check state before operations: Verify state before performing actions
- Clean up subscriptions: Unsubscribe from events when done
- Use appropriate service: Each service has a specific purpose - use the right one