Rationale
WinForms has always been used far beyond classic back-office desktop forms. Many production applications run as a single, unattended workstation for production data acquisition: booking times, reading data from production machines, or working with I/O cards to count, measure, weigh, and convert physical signals. WinForms is also used for display machines and information boards such as timetables in railway stations, bus stations, airports, advertising displays, stadiums, theaters, malls, and public directories. It is also widely used for point-of-sales and ticketing UIs, for example in public transportation, clubs, swimming halls, and other public venues.
These scenarios often need a predictable kiosk-style surface: a fullscreen form, optional taskbar coverage, controlled topmost behavior, suppressed display/system sleep, mouse pointer hiding after inactivity, and reliable notification when the user or system wakes the kiosk experience. Customers have often solved these needs with outlandish or fragile approaches that fight the shell, power management, input routing, or modern Windows behavior. Those workarounds can become migration blockers when customers move long-lived WinForms applications to newer Windows versions.
KioskModeManager provides a first-party WinForms component for these scenarios. It gives applications a designer-friendly way to manage the common kiosk mechanics while preserving WinForms composition patterns. The component intentionally exposes ContainerControl instead of Form so it can be placed on either a Form or a UserControl at design time. A component placed on a UserControl can resolve the containing form at runtime, which keeps designer behavior consistent across common WinForms layouts.
API Proposal
namespace System.Windows.Forms;
public class KioskModeManager : Component, ISupportInitialize
{
public KioskModeManager();
public KioskModeManager(IContainer container);
public ContainerControl? ContainerControl { get; set; }
public bool EscapeExitsFullScreen { get; set; }
public bool HideTaskbar { get; set; }
public bool IsFullScreen { get; }
public int MousePointerAutoHideDelay { get; set; }
public bool SuppressPowerSaving { get; set; }
public Keys ToggleFullScreenKey { get; set; }
public bool TopMostInFullScreen { get; set; }
public event EventHandler? ContainerControlChanged;
public event EventHandler? EscapeExitsFullScreenChanged;
public event EventHandler? FullScreenChanged;
public event EventHandler? HideTaskbarChanged;
public event EventHandler? MousePointerAutoHideDelayChanged;
public event EventHandler? SuppressPowerSavingChanged;
public event EventHandler? ToggleFullScreenKeyChanged;
public event EventHandler? TopMostInFullScreenChanged;
public event KioskModeWakeupEventHandler? Wakeup;
public void ToggleFullScreen();
protected virtual void OnContainerControlChanged(EventArgs e);
protected virtual void OnEscapeExitsFullScreenChanged(EventArgs e);
protected virtual void OnFullScreenChanged(EventArgs e);
protected virtual void OnHideTaskbarChanged(EventArgs e);
protected virtual void OnMousePointerAutoHideDelayChanged(EventArgs e);
protected virtual void OnSuppressPowerSavingChanged(EventArgs e);
protected virtual void OnToggleFullScreenKeyChanged(EventArgs e);
protected virtual void OnTopMostInFullScreenChanged(EventArgs e);
protected virtual void OnWakeup(KioskModeWakeupEventArgs e);
}
public enum KioskModeWakeupSource
{
Keyboard = 0,
Mouse = 1,
PowerResume = 2,
Session = 3,
}
public class KioskModeWakeupEventArgs : EventArgs
{
public KioskModeWakeupEventArgs(KioskModeWakeupSource source);
public KioskModeWakeupSource Source { get; }
}
public delegate void KioskModeWakeupEventHandler(object? sender, KioskModeWakeupEventArgs e);
API Usage
public partial class MainForm : Form
{
private readonly KioskModeManager _kioskModeManager;
public MainForm()
{
InitializeComponent();
_kioskModeManager = new KioskModeManager
{
ContainerControl = this,
HideTaskbar = true,
TopMostInFullScreen = true,
EscapeExitsFullScreen = true,
MousePointerAutoHideDelay = 3000,
SuppressPowerSaving = true,
};
_kioskModeManager.Wakeup += (sender, e) =>
{
if (e.Source is KioskModeWakeupSource.Mouse or KioskModeWakeupSource.Keyboard)
{
// Refresh kiosk UI, restart inactivity timers, or check whether fullscreen should remain active.
}
};
if (!_kioskModeManager.IsFullScreen)
{
_kioskModeManager.ToggleFullScreen();
}
}
}
Alternative Designs
- Expose a
Form property instead of ContainerControl. This was rejected because the component can be placed on a UserControl at design time and resolve the containing form later.
- Expose separate
EnterFullScreen and ExitFullScreen methods. This was rejected because IsFullScreen plus ToggleFullScreen is sufficient for callers that need an explicit target state.
- Use only the form's
KeyDown event and KeyPreview. This is simple but invasive because it changes form keyboard routing and does not provide a general wakeup signal for mouse or power/session activity.
- Use a simple
EventHandler for Wakeup. A dedicated event args type is preferred so applications can distinguish keyboard, mouse, power resume, and session activity.
- Include voice wake, network wake, or explicit wake timers in the first version. These were excluded because voice and network wake are hardware/OS/application-specific, and wake timers require a separate native timer/power-policy design.
Risks
- Incorrect native handle lifetime could leak power request or hook handles; implementation must close handles and unhook deterministically.
- Cursor hiding must remain balanced because
Cursor.Hide/Cursor.Show affect an internal display counter.
- Hook/message observation can affect input performance or behavior if implemented globally; thread-scoped observation is preferred.
- Power management APIs may fail due to OS policy or permissions and must not leave the component in a misleading partial state.
Will this feature affect UI controls?
Yes. The component changes fullscreen state for the resolved form, can hide the mouse pointer while fullscreen, and can suppress display/system sleep. Designer support is required through localized property categories/descriptions, CodeDOM serialization-safe defaults, and behavior that works when the component is dropped on either a Form or a UserControl. No new localized runtime UI text is expected beyond design-time descriptions and exception messages.
Status Checklist
Rationale
WinForms has always been used far beyond classic back-office desktop forms. Many production applications run as a single, unattended workstation for production data acquisition: booking times, reading data from production machines, or working with I/O cards to count, measure, weigh, and convert physical signals. WinForms is also used for display machines and information boards such as timetables in railway stations, bus stations, airports, advertising displays, stadiums, theaters, malls, and public directories. It is also widely used for point-of-sales and ticketing UIs, for example in public transportation, clubs, swimming halls, and other public venues.
These scenarios often need a predictable kiosk-style surface: a fullscreen form, optional taskbar coverage, controlled topmost behavior, suppressed display/system sleep, mouse pointer hiding after inactivity, and reliable notification when the user or system wakes the kiosk experience. Customers have often solved these needs with outlandish or fragile approaches that fight the shell, power management, input routing, or modern Windows behavior. Those workarounds can become migration blockers when customers move long-lived WinForms applications to newer Windows versions.
KioskModeManagerprovides a first-party WinForms component for these scenarios. It gives applications a designer-friendly way to manage the common kiosk mechanics while preserving WinForms composition patterns. The component intentionally exposesContainerControlinstead ofFormso it can be placed on either aFormor aUserControlat design time. A component placed on aUserControlcan resolve the containing form at runtime, which keeps designer behavior consistent across common WinForms layouts.API Proposal
API Usage
Alternative Designs
Formproperty instead ofContainerControl. This was rejected because the component can be placed on aUserControlat design time and resolve the containing form later.EnterFullScreenandExitFullScreenmethods. This was rejected becauseIsFullScreenplusToggleFullScreenis sufficient for callers that need an explicit target state.KeyDownevent andKeyPreview. This is simple but invasive because it changes form keyboard routing and does not provide a general wakeup signal for mouse or power/session activity.EventHandlerforWakeup. A dedicated event args type is preferred so applications can distinguish keyboard, mouse, power resume, and session activity.Risks
Cursor.Hide/Cursor.Showaffect an internal display counter.Will this feature affect UI controls?
Yes. The component changes fullscreen state for the resolved form, can hide the mouse pointer while fullscreen, and can suppress display/system sleep. Designer support is required through localized property categories/descriptions, CodeDOM serialization-safe defaults, and behavior that works when the component is dropped on either a
Formor aUserControl. No new localized runtime UI text is expected beyond design-time descriptions and exception messages.Status Checklist
api-suggestionlabelapi-ready-for-reviewblockinglabel to expedite the review appointmentapi-approved