Skip to content

[API Suggestion] Consider Control/Window Cloaking During Initialization #13233

@KlausLoeffelmann

Description

@KlausLoeffelmann

TL;DR

Implement a cloaking mechanism for WinForms controls during initialization to eliminate jarring visual flashes, particularly critical for dark mode users and those with photosensitivity. This approach leverages Windows DWM cloaking flags to keep controls hidden until fully themed and ready, significantly improving accessibility compliance and user experience across all applications.

Rationale

The current WinForms runtime suffers from momentary visual flashing when controls are created or initialized. This occurs because the Desktop Window Manager (DWM) applies default white rendering before the application can override with themed styling. For users with dark mode enabled or those with photosensitivity conditions, this creates an uncomfortable white flash effect. (I am target-audience here, it REALLY does!!)

This issue represents both a user-experience-problem and a significant accessibility concern. Visual flashing during UI transitions can trigger adverse reactions in users with photosensitive epilepsy, migraines, or visual processing sensitivities. Modern accessibility standards (WCAG 2.1) explicitly recommend avoiding content that flashes to prevent these issues.

Similar problems were previously resolved in Windows components like File Explorer and addressed in Chromium-based browsers, demonstrating that this issue is recognized and solvable at the platform level. The WinForms runtime should implement an equivalent solution to ensure consistent visual experiences, especially for dark mode and high-contrast scenarios.

30,000-Feet View of the principal Approach

I propose implementing a standardized cloaking mechanism in the WinForms runtime that would:

  1. Temporarily make controls/windows invisible during initialization using DWM cloaking flags, either by a global setting which leads to that behavior implicitly, or with a per-instance-approach by changing certain behaviors on control itself.

  2. TBD: Scope of cloaking/duration of cloaking:
    a) Only Pre-Filling background

    • Pre-fill the background with the appropriate theme color before rendering begins.
    • Remove cloak.

    b) Whole initialization process:

    • Pre-fill the background with the appropriate theme color before rendering begins.
    • Complete all initialization, property setting, and child control population.
    • Remove the cloak only when the control is fully ready to display.

New APIs on Application

An additional setting similar to the SetHighDpiMode method or the HighDpiMode property on Application:

Application.SetCloakControlsMode(Never|Always|TypeBased|InstanceBased) with its default as backwards compatible: Never.

For the Options CloakControlsMode.TypeBased and CloakControlsMode.InstanceBased we would need a global event handler based on Application (rough idea):

The EventArgs needed:

/// <summary>
/// Event arguments for cloaking decisions.
/// </summary>
public class CloakEventArgs : EventArgs
{
    /// <summary>
    /// Initializes a new instance of this class.
    /// </summary>
    public CloakEventArgs(Type controlType, Control? control = null)
    {
        ControlType = controlType;
        Control = control;
        ShouldCloak = false; // Default to false
    }

    /// <summary>
    ///  The type of control being evaluated for cloaking.
    /// </summary>
    public Type ControlType { get; }

    /// <summary>
    ///  The instance of the control being evaluated for cloaking (if applicable).
    /// </summary>
    public Control? Control { get; set; }

    /// <summary>
    ///  Gets or sets whether the control should be cloaked.
    ///  Set to true by event handlers to enable cloaking.
    /// </summary>
    public bool ShouldCloak { get; set; }
}

Then, the individual decision for cloaking a type for example, could look something like this:

static class Program
{
    [STAThread]
    static void Main()
    {
        Application... (Init stuff)
        
        // Register cloaking handlers
        Application.CloakingRequested += OnCloakingRequested;
        
        Application.Run(new MainForm());
    }
    
    private static void OnCloakingRequested(object sender, CloakEventArgs e)
    {
        // Type-level decisions
        Type type = e.ControlType;
        
        // Check for specific types that should be cloaked
        if (type == typeof(ToolStrip) || 
            type == typeof(MenuStrip) || 
            type == typeof(StatusStrip))
        {
            e.ShouldCloak = true;
            return;
        }
        
        // Check for types in specific namespaces
        string ns = type.Namespace ?? "";
        if (ns.StartsWith("MyCompany.Controls.Special"))
        {
            e.ShouldCloak = true;
            return;
        }
        
        // Default is false (already set in the event args)
    }
}

By implementing this enhancement, the .NET WinForms runtime would significantly improve the experience for users of dark mode and those with accessibility needs, bringing it in line with modern UI framework expectations and accessibility standards.

There are several approaches then for the actual cloaking approach on windows level, which are under investigation and subject for follow-ups and amendments.

Why not just having a respective CloakOnInit property on Control?

Sounds way easier right? Just implement it ambient, and we would be done.
Well, I think the problem is the way, that the WinForms Desiger's CodeDOM serialization has been originally ... designed. Namely, the order in which properties should be set, must not matter, except where it is absolutely necessary in which cases, we'd need to use ISupportInitialization. And that does not fly to retro-fit on control AT ALL.

List of new APIs

TBD.

Metadata

Metadata

Labels

At risk 10-30Feature is with 10%-30% prob. delayed/at risk due to internal reprioritization/resource scarceness.a11y-WCAG2.2api-suggestion(1) Early API idea and discussion, it is NOT ready for implementationarea-DarkModeIssues relating to Dark Mode feature

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions