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. When the component is sited (for example, dropped onto a designer surface) and ContainerControl has not been set explicitly, it automatically resolves the root component of the designer host (typically the owning Form or UserControl) and assigns it as the ContainerControl. An explicitly assigned ContainerControl is never overwritten.
The FullScreen and WakeUpCommand members are bindable so the component fits modern, MVVM-style WinForms applications: FullScreen supports two-way data binding to a view-model state, and WakeUpCommand lets a view-model react to wakeup activity without subscribing to the Wakeup event in code-behind.
API Proposal
namespace System.Windows.Forms;
using System.Windows.Input;
public class KioskModeManager : Component, ISupportInitialize
{
public KioskModeManager();
public KioskModeManager(IContainer container);
public ContainerControl? ContainerControl { get; set; }
public bool EscapeExitsFullScreen { get; set; }
[Bindable(true)]
public bool FullScreen { get; set; }
public bool HideTaskbar { get; set; }
public int MousePointerAutoHideDelay { get; set; }
public bool SuppressPowerSaving { get; set; }
public Keys ToggleFullScreenKey { get; set; }
public bool TopMostInFullScreen { get; set; }
[Bindable(true)]
public ICommand? WakeUpCommand { get; set; }
public override ISite? Site { get; set; }
public event EventHandler? ContainerControlChanged;
public event EventHandler? FullScreenChanged;
public event KioskModeWakeupEventHandler? Wakeup;
public void ToggleFullScreen();
protected virtual void OnContainerControlChanged(EventArgs e);
protected virtual void OnFullScreenChanged(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);
Changes from the original proposal
- The read-only
IsFullScreen property is replaced by a bindable, read/write FullScreen property so it can participate in two-way data binding. Setting FullScreen = true enters fullscreen and FullScreen = false restores the saved form state.
- A bindable
WakeUpCommand (ICommand) is added. It is executed on every Wakeup, receiving the wakeup source name (KioskModeWakeupSource.ToString()) as the command parameter so the command stays independent of the WinForms-specific enum type.
- The per-property
…Changed events and their On…Changed methods are removed for EscapeExitsFullScreen, HideTaskbar, MousePointerAutoHideDelay, SuppressPowerSaving, ToggleFullScreenKey, and TopMostInFullScreen. Only ContainerControlChanged, FullScreenChanged, and Wakeup remain.
Site is overridden so that, when the component is sited and ContainerControl has not been set explicitly, the designer host's root component is assigned as the ContainerControl.
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.FullScreen)
{
_kioskModeManager.ToggleFullScreen();
}
}
}
MVVM-style usage with data binding:
// Two-way binding of the fullscreen state and a command that runs on every wakeup.
_kioskModeManager.DataBindings.Add(
nameof(KioskModeManager.FullScreen),
viewModel,
nameof(MainViewModel.IsKioskFullScreen),
formattingEnabled: false,
DataSourceUpdateMode.OnPropertyChanged);
_kioskModeManager.WakeUpCommand = viewModel.WakeUpCommand;
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 the bindable FullScreen property plus ToggleFullScreen is sufficient for callers that need an explicit target state.
- Keep
IsFullScreen as a read-only property. This was rejected because a read/write, bindable FullScreen property enables two-way data binding for MVVM-style applications.
- Expose per-property
…Changed events for every setting. This was rejected as unnecessary API surface; data binding for the bindable members and the FullScreenChanged/ContainerControlChanged events cover the meaningful change scenarios.
- 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. When the component is sited (for example, dropped onto a designer surface) andContainerControlhas not been set explicitly, it automatically resolves the root component of the designer host (typically the owningFormorUserControl) and assigns it as theContainerControl. An explicitly assignedContainerControlis never overwritten.The
FullScreenandWakeUpCommandmembers are bindable so the component fits modern, MVVM-style WinForms applications:FullScreensupports two-way data binding to a view-model state, andWakeUpCommandlets a view-model react to wakeup activity without subscribing to theWakeupevent in code-behind.API Proposal
API Usage
MVVM-style usage with data binding:
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 because the bindableFullScreenproperty plusToggleFullScreenis sufficient for callers that need an explicit target state.IsFullScreenas a read-only property. This was rejected because a read/write, bindableFullScreenproperty enables two-way data binding for MVVM-style applications.…Changedevents for every setting. This was rejected as unnecessary API surface; data binding for the bindable members and theFullScreenChanged/ContainerControlChangedevents cover the meaningful change scenarios.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