Skip to content

Commit b16ca39

Browse files
Remove Experimental attribute for dark mode and add disclaimer to Application.SetColorMode.
1 parent 8a44096 commit b16ca39

File tree

48 files changed

+118
-173
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+118
-173
lines changed

src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/ApplyApplicationDefaultsEventArgs.vb

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ Namespace Microsoft.VisualBasic.ApplicationServices
1717
Public Class ApplyApplicationDefaultsEventArgs
1818
Inherits EventArgs
1919

20-
#Disable Warning WFO5001
21-
2220
Friend Sub New(minimumSplashScreenDisplayTime As Integer,
2321
highDpiMode As HighDpiMode,
2422
colorMode As SystemColorMode)
@@ -28,13 +26,10 @@ Namespace Microsoft.VisualBasic.ApplicationServices
2826
Me.ColorMode = colorMode
2927
End Sub
3028

31-
#Enable Warning WFO5001
32-
3329
''' <summary>
3430
''' Setting this property inside the event handler determines the
3531
''' <see cref="Application.ColorMode"/> for the application.
3632
''' </summary>
37-
<Experimental(DiagnosticIDs.ExperimentalDarkMode, UrlFormat:=DiagnosticIDs.UrlFormat)>
3833
Public Property ColorMode As SystemColorMode
3934

4035
''' <summary>

src/Microsoft.VisualBasic.Forms/src/Microsoft/VisualBasic/ApplicationServices/WindowsFormsApplicationBase.vb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,6 @@ Namespace Microsoft.VisualBasic.ApplicationServices
194194
''' <value>
195195
''' The <see cref="SystemColorMode"/> that the application is running in.
196196
''' </value>
197-
<Experimental(DiagnosticIDs.ExperimentalDarkMode, UrlFormat:=DiagnosticIDs.UrlFormat)>
198197
<EditorBrowsable(EditorBrowsableState.Never)>
199198
Protected Property ColorMode As SystemColorMode
200199
Get

src/System.Windows.Forms/PublicAPI.Shipped.txt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,30 @@
1818
[WFO5001]virtual System.Windows.Forms.Form.OnFormCaptionBackColorChanged(System.EventArgs! e) -> void
1919
[WFO5001]virtual System.Windows.Forms.Form.OnFormCaptionTextColorChanged(System.EventArgs! e) -> void
2020
[WFO5001]virtual System.Windows.Forms.Form.OnFormCornerPreferenceChanged(System.EventArgs! e) -> void
21+
[WFO5002]static System.Windows.Forms.TaskDialog.ShowDialogAsync(nint hwndOwner, System.Windows.Forms.TaskDialogPage! page, System.Windows.Forms.TaskDialogStartupLocation startupLocation = System.Windows.Forms.TaskDialogStartupLocation.CenterOwner) -> System.Threading.Tasks.Task<System.Windows.Forms.TaskDialogButton!>!
22+
[WFO5002]static System.Windows.Forms.TaskDialog.ShowDialogAsync(System.Windows.Forms.IWin32Window! owner, System.Windows.Forms.TaskDialogPage! page, System.Windows.Forms.TaskDialogStartupLocation startupLocation = System.Windows.Forms.TaskDialogStartupLocation.CenterOwner) -> System.Threading.Tasks.Task<System.Windows.Forms.TaskDialogButton!>!
23+
[WFO5002]static System.Windows.Forms.TaskDialog.ShowDialogAsync(System.Windows.Forms.TaskDialogPage! page, System.Windows.Forms.TaskDialogStartupLocation startupLocation = System.Windows.Forms.TaskDialogStartupLocation.CenterScreen) -> System.Threading.Tasks.Task<System.Windows.Forms.TaskDialogButton!>!
24+
[WFO5002]System.Windows.Forms.Form.ShowAsync(System.Windows.Forms.IWin32Window? owner = null) -> System.Threading.Tasks.Task!
25+
[WFO5002]System.Windows.Forms.Form.ShowDialogAsync() -> System.Threading.Tasks.Task<System.Windows.Forms.DialogResult>!
26+
[WFO5002]System.Windows.Forms.Form.ShowDialogAsync(System.Windows.Forms.IWin32Window! owner) -> System.Threading.Tasks.Task<System.Windows.Forms.DialogResult>!
27+
[WFO5002]static System.Windows.Forms.TaskDialog.ShowDialogAsync(nint hwndOwner, System.Windows.Forms.TaskDialogPage! page, System.Windows.Forms.TaskDialogStartupLocation startupLocation = System.Windows.Forms.TaskDialogStartupLocation.CenterOwner) -> System.Threading.Tasks.Task<System.Windows.Forms.TaskDialogButton!>!
28+
[WFO5002]static System.Windows.Forms.TaskDialog.ShowDialogAsync(System.Windows.Forms.IWin32Window! owner, System.Windows.Forms.TaskDialogPage! page, System.Windows.Forms.TaskDialogStartupLocation startupLocation = System.Windows.Forms.TaskDialogStartupLocation.CenterOwner) -> System.Threading.Tasks.Task<System.Windows.Forms.TaskDialogButton!>!
29+
[WFO5002]static System.Windows.Forms.TaskDialog.ShowDialogAsync(System.Windows.Forms.TaskDialogPage! page, System.Windows.Forms.TaskDialogStartupLocation startupLocation = System.Windows.Forms.TaskDialogStartupLocation.CenterScreen) -> System.Threading.Tasks.Task<System.Windows.Forms.TaskDialogButton!>!
30+
[WFO5002]System.Windows.Forms.Form.ShowAsync(System.Windows.Forms.IWin32Window? owner = null) -> System.Threading.Tasks.Task!
31+
[WFO5002]System.Windows.Forms.Form.ShowDialogAsync() -> System.Threading.Tasks.Task<System.Windows.Forms.DialogResult>!
32+
[WFO5002]System.Windows.Forms.Form.ShowDialogAsync(System.Windows.Forms.IWin32Window! owner) -> System.Threading.Tasks.Task<System.Windows.Forms.DialogResult>!
33+
[WFO5002]static System.Windows.Forms.TaskDialog.ShowDialogAsync(nint hwndOwner, System.Windows.Forms.TaskDialogPage! page, System.Windows.Forms.TaskDialogStartupLocation startupLocation = System.Windows.Forms.TaskDialogStartupLocation.CenterOwner) -> System.Threading.Tasks.Task<System.Windows.Forms.TaskDialogButton!>!
34+
[WFO5002]static System.Windows.Forms.TaskDialog.ShowDialogAsync(System.Windows.Forms.IWin32Window! owner, System.Windows.Forms.TaskDialogPage! page, System.Windows.Forms.TaskDialogStartupLocation startupLocation = System.Windows.Forms.TaskDialogStartupLocation.CenterOwner) -> System.Threading.Tasks.Task<System.Windows.Forms.TaskDialogButton!>!
35+
[WFO5002]static System.Windows.Forms.TaskDialog.ShowDialogAsync(System.Windows.Forms.TaskDialogPage! page, System.Windows.Forms.TaskDialogStartupLocation startupLocation = System.Windows.Forms.TaskDialogStartupLocation.CenterScreen) -> System.Threading.Tasks.Task<System.Windows.Forms.TaskDialogButton!>!
36+
[WFO5002]System.Windows.Forms.Form.ShowAsync(System.Windows.Forms.IWin32Window? owner = null) -> System.Threading.Tasks.Task!
37+
[WFO5002]System.Windows.Forms.Form.ShowDialogAsync() -> System.Threading.Tasks.Task<System.Windows.Forms.DialogResult>!
38+
[WFO5002]System.Windows.Forms.Form.ShowDialogAsync(System.Windows.Forms.IWin32Window! owner) -> System.Threading.Tasks.Task<System.Windows.Forms.DialogResult>!
39+
[WFO5002]static System.Windows.Forms.TaskDialog.ShowDialogAsync(nint hwndOwner, System.Windows.Forms.TaskDialogPage! page, System.Windows.Forms.TaskDialogStartupLocation startupLocation = System.Windows.Forms.TaskDialogStartupLocation.CenterOwner) -> System.Threading.Tasks.Task<System.Windows.Forms.TaskDialogButton!>!
40+
[WFO5002]static System.Windows.Forms.TaskDialog.ShowDialogAsync(System.Windows.Forms.IWin32Window! owner, System.Windows.Forms.TaskDialogPage! page, System.Windows.Forms.TaskDialogStartupLocation startupLocation = System.Windows.Forms.TaskDialogStartupLocation.CenterOwner) -> System.Threading.Tasks.Task<System.Windows.Forms.TaskDialogButton!>!
41+
[WFO5002]static System.Windows.Forms.TaskDialog.ShowDialogAsync(System.Windows.Forms.TaskDialogPage! page, System.Windows.Forms.TaskDialogStartupLocation startupLocation = System.Windows.Forms.TaskDialogStartupLocation.CenterScreen) -> System.Threading.Tasks.Task<System.Windows.Forms.TaskDialogButton!>!
42+
[WFO5002]System.Windows.Forms.Form.ShowAsync(System.Windows.Forms.IWin32Window? owner = null) -> System.Threading.Tasks.Task!
43+
[WFO5002]System.Windows.Forms.Form.ShowDialogAsync() -> System.Threading.Tasks.Task<System.Windows.Forms.DialogResult>!
44+
[WFO5002]System.Windows.Forms.Form.ShowDialogAsync(System.Windows.Forms.IWin32Window! owner) -> System.Threading.Tasks.Task<System.Windows.Forms.DialogResult>!
2145
[WFO5003]System.Windows.Forms.IAsyncDropTarget
2246
[WFO5003]System.Windows.Forms.IAsyncDropTarget.OnAsyncDragDrop(System.Windows.Forms.DragEventArgs! e) -> void
2347
~abstract System.Windows.Forms.DataGridColumnStyle.Commit(System.Windows.Forms.CurrencyManager dataSource, int rowNum) -> bool

src/System.Windows.Forms/PublicAPI.Unshipped.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,23 @@ System.Windows.Forms.Form.ShowAsync(System.Windows.Forms.IWin32Window? owner = n
55
System.Windows.Forms.Form.ShowDialogAsync() -> System.Threading.Tasks.Task<System.Windows.Forms.DialogResult>!
66
System.Windows.Forms.Form.ShowDialogAsync(System.Windows.Forms.IWin32Window! owner) -> System.Threading.Tasks.Task<System.Windows.Forms.DialogResult>!
77
System.Windows.Forms.VisualStyles.ComboBoxState.Focused = 5 -> System.Windows.Forms.VisualStyles.ComboBoxState
8+
static System.Windows.Forms.Application.SetColorMode(System.Windows.Forms.SystemColorMode systemColorMode) -> void
9+
System.Windows.Forms.ControlStyles.ApplyThemingImplicitly = 524288 -> System.Windows.Forms.ControlStyles
10+
System.Windows.Forms.Form.FormBorderColorChanged -> System.EventHandler?
11+
System.Windows.Forms.Form.FormCaptionBackColorChanged -> System.EventHandler?
12+
System.Windows.Forms.Form.FormCaptionTextColorChanged -> System.EventHandler?
13+
System.Windows.Forms.Form.FormCornerPreferenceChanged -> System.EventHandler?
14+
System.Windows.Forms.FormCornerPreference
15+
System.Windows.Forms.FormCornerPreference.Default = 0 -> System.Windows.Forms.FormCornerPreference
16+
System.Windows.Forms.FormCornerPreference.DoNotRound = 1 -> System.Windows.Forms.FormCornerPreference
17+
System.Windows.Forms.FormCornerPreference.Round = 2 -> System.Windows.Forms.FormCornerPreference
18+
System.Windows.Forms.FormCornerPreference.RoundSmall = 3 -> System.Windows.Forms.FormCornerPreference
19+
System.Windows.Forms.SystemColorMode
20+
System.Windows.Forms.SystemColorMode.Classic = 0 -> System.Windows.Forms.SystemColorMode
21+
System.Windows.Forms.SystemColorMode.Dark = 2 -> System.Windows.Forms.SystemColorMode
22+
System.Windows.Forms.SystemColorMode.System = 1 -> System.Windows.Forms.SystemColorMode
23+
virtual System.Windows.Forms.Form.OnFormBorderColorChanged(System.EventArgs! e) -> void
24+
virtual System.Windows.Forms.Form.OnFormCaptionBackColorChanged(System.EventArgs! e) -> void
25+
virtual System.Windows.Forms.Form.OnFormCaptionTextColorChanged(System.EventArgs! e) -> void
26+
virtual System.Windows.Forms.Form.OnFormCornerPreferenceChanged(System.EventArgs! e) -> void
27+
System.Windows.Forms.VisualStyles.ComboBoxState.Focused = 5 -> System.Windows.Forms.VisualStyles.ComboBoxState

src/System.Windows.Forms/System/Windows/Forms/Application.cs

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using System.Globalization;
77
using System.Reflection;
88
using System.Text;
9-
using System.Windows.Forms.Analyzers.Diagnostics;
109
using System.Windows.Forms.VisualStyles;
1110
using Microsoft.Office;
1211
using Microsoft.Win32;
@@ -44,9 +43,7 @@ public sealed partial class Application
4443
private static readonly Lock s_internalSyncObject = new();
4544
private static bool s_useWaitCursor;
4645

47-
#pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
4846
private static SystemColorMode? s_colorMode;
49-
#pragma warning restore WFO5001
5047

5148
private const string DarkModeKeyPath = "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
5249
private const string DarkModeKey = "AppsUseLightTheme";
@@ -250,7 +247,6 @@ internal static bool CustomThreadExceptionHandlerAttached
250247
/// static (shared in VB) <see cref="SystemColorMode"/> property.
251248
/// </para>
252249
/// </remarks>
253-
[Experimental(DiagnosticIDs.ExperimentalDarkMode, UrlFormat = DiagnosticIDs.UrlFormat)]
254250
public static SystemColorMode ColorMode => s_colorMode ?? SystemColorMode.Classic;
255251

256252
/// <summary>
@@ -259,31 +255,68 @@ internal static bool CustomThreadExceptionHandlerAttached
259255
internal static bool ColorModeSet => s_colorMode is not null;
260256

261257
/// <summary>
262-
/// Sets the default color mode (dark mode) for the application.
258+
/// Sets the default color mode (Classic/Light Mode, Dark Mode, or the system-defined Light/Dark Mode) for the entire application.
263259
/// </summary>
264-
/// <param name="systemColorMode">The application's default color mode (dark mode) to set.</param>
260+
/// <param name="systemColorMode">The application's default color mode to set.</param>
265261
/// <remarks>
266262
/// <para>
267-
/// You should use this method to set the default color mode (dark mode) for the application. Set it,
268-
/// before creating any UI elements, to ensure that the correct color mode is used. You can set it to
269-
/// dark mode (<see cref="SystemColorMode.Dark"/>), light mode (<see cref="SystemColorMode.Classic"/>)
270-
/// or to the system setting (<see cref="SystemColorMode.System"/>).
263+
/// Use this method to set the color mode for the entire application. Set it before creating any UI
264+
/// elements to ensure the correct color mode is applied. You can choose Dark Mode
265+
/// (<see cref="SystemColorMode.Dark"/>), Classic (light) Mode (<see cref="SystemColorMode.Classic"/>),
266+
/// or the system-defined mode (<see cref="SystemColorMode.System"/>).
271267
/// </para>
272268
/// <para>
273-
/// If you set it to <see cref="SystemColorMode.System"/>, the actual color mode is determined by the
274-
/// Windows system settings. If the system setting is changed, the application will not automatically
275-
/// adapt to the new setting.
269+
/// If you set <see cref="SystemColorMode.System"/>, the actual color mode is determined by the Windows system settings.
270+
/// If the system setting changes, the application will not automatically adapt; you must restart the application
271+
/// to apply the new system setting.
276272
/// </para>
277273
/// <para>
278-
/// Note that the dark color mode is only available from Windows 11 on or later versions. If the system
279-
/// is set to a high contrast mode, the dark mode is not available.
274+
/// Note that Dark Mode is only available on Windows 11 and later. If Windows is set to High Contrast mode,
275+
/// that mode always takes precedence over other settings.
280276
/// </para>
281277
/// <para>
282-
/// <b>Note for Visual Basic:</b> If you are using the Visual Basic Application Framework, you should set the
283-
/// color mode by handling the Application Events (see "WindowsFormsApplicationBase.ApplyApplicationDefaults").
278+
/// <b>Note for Visual Basic:</b> If you are using the Visual Basic Application Framework, set the color mode
279+
/// by handling the Application Events (see "WindowsFormsApplicationBase.ApplyApplicationDefaults").
284280
/// </para>
281+
/// <para>
282+
/// <b>Important Considerations for Dark Mode in WinForms:</b>
283+
/// </para>
284+
/// <list type="bullet">
285+
/// <item>
286+
/// <description>
287+
/// <b>WinForms and Win32 Limitations:</b> WinForms is a managed wrapper around native Win32 controls.
288+
/// This architecture introduces inherent limitations in theming and rendering, especially in Dark Mode.
289+
/// While Windows continues to evolve its support for theming, some constraints remain.
290+
/// </description>
291+
/// </item>
292+
/// <item>
293+
/// <description>
294+
/// <b>Rendering Limitations:</b> Certain controls may not render perfectly in Dark Mode due to underlying Win32
295+
/// behavior. These imperfections are expected and will not be treated as bugs.
296+
/// </description>
297+
/// </item>
298+
/// <item>
299+
/// <description>
300+
/// <b>Security and Compatibility First:</b> Security and backward compatibility are prioritized over perfect visual fidelity.
301+
/// Changes that risk breaking classic rendering or introduce regressions will be avoided.
302+
/// </description>
303+
/// </item>
304+
/// <item>
305+
/// <description>
306+
/// <b>Ongoing Improvements:</b> As Windows improves Win32 theming, WinForms will adapt accordingly. Dark Mode rendering
307+
/// will improve over time, but not all issues will be resolved immediately.
308+
/// </description>
309+
/// </item>
310+
/// <item>
311+
/// <description>
312+
/// <b>Contrast and Accessibility Edge Cases:</b> Some edge cases may result in suboptimal contrast or may not meet certain
313+
/// accessibility guidelines. While Dark Mode addresses major accessibility concerns for many users (such as reducing eye
314+
/// strain from bright screens), if your application requires strict contrast compliance, we recommend using
315+
/// Classic (light) mode or High Contrast mode.
316+
/// </description>
317+
/// </item>
318+
/// </list>
285319
/// </remarks>
286-
[Experimental(DiagnosticIDs.ExperimentalDarkMode, UrlFormat = DiagnosticIDs.UrlFormat)]
287320
public static void SetColorMode(SystemColorMode systemColorMode)
288321
{
289322
try
@@ -306,12 +339,16 @@ public static void SetColorMode(SystemColorMode systemColorMode)
306339
}
307340
finally
308341
{
342+
#pragma warning disable SYSLIB5002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
309343
bool useAlternateColorSet = SystemColors.UseAlternativeColorSet;
344+
#pragma warning restore SYSLIB5002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
310345
bool darkModeEnabled = IsDarkModeEnabled;
311346

312347
if (useAlternateColorSet != darkModeEnabled)
313348
{
349+
#pragma warning disable SYSLIB5002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
314350
SystemColors.UseAlternativeColorSet = darkModeEnabled;
351+
#pragma warning restore SYSLIB5002 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
315352
NotifySystemEventsOfColorChange();
316353
}
317354
}
@@ -362,7 +399,6 @@ static void NotifySystemEventsOfColorChange()
362399
/// SystemColorModes is not supported, if the Windows OS <c>High Contrast Mode</c> has been enabled in the system settings.
363400
/// </para>
364401
/// </remarks>
365-
[Experimental(DiagnosticIDs.ExperimentalDarkMode, UrlFormat = DiagnosticIDs.UrlFormat)]
366402
public static SystemColorMode SystemColorMode =>
367403
GetSystemColorModeInternal() == 0
368404
? SystemColorMode.Dark
@@ -400,7 +436,6 @@ private static int GetSystemColorModeInternal()
400436
/// Gets a value indicating whether the application is running in a dark system color context.
401437
/// Note: In a high contrast mode, this will always return <see langword="false"/>.
402438
/// </summary>
403-
[Experimental(DiagnosticIDs.ExperimentalDarkMode, UrlFormat = DiagnosticIDs.UrlFormat)]
404439
public static bool IsDarkModeEnabled =>
405440
!SystemInformation.HighContrast
406441
&& (ColorMode == SystemColorMode.Dark

0 commit comments

Comments
 (0)