Skip to content

Commit f9b3ed3

Browse files
Fix dark mode issues.
Add plausibility unit tests. Apply backwards-compatibility (10->9) fix. Refactor System-handling for SetColor. Fix XML comments and property value handling in Formxxx properties. Fix bug where in Visual Basic VisualStyles no longer get applied. Fix raising wrong event on changing FormCaptionTextColor.
1 parent 701b3b1 commit f9b3ed3

File tree

4 files changed

+197
-47
lines changed

4 files changed

+197
-47
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,10 @@ Namespace Microsoft.VisualBasic.ApplicationServices
550550
Debug.Assert(dpiSetResult, "We could net set the HighDpiMode.")
551551

552552
' Now, let's set VisualStyles and ColorMode:
553+
If (_enableVisualStyles) Then
554+
Application.EnableVisualStyles()
555+
End If
556+
553557
Application.SetColorMode(_colorMode)
554558

555559
#Enable Warning WFO5001 ' Type is for evaluation purposes only and is subject to change or removal in future updates.

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

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ public sealed partial class Application
4545
private static bool s_useWaitCursor;
4646

4747
#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.
48-
private static SystemColorMode? s_systemColorMode;
48+
private static SystemColorMode? s_colorMode;
4949
#pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
5050

5151
private const string DarkModeKeyPath = "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
5252
private const string DarkModeKey = "AppsUseLightTheme";
53-
private const int DarkModeNotAvailable = -1;
53+
private const int SystemDarkModeDisabled = 1;
5454

5555
/// <summary>
5656
/// Events the user can hook into
@@ -247,27 +247,51 @@ internal static bool CustomThreadExceptionHandlerAttached
247247
=> ThreadContext.FromCurrent().CustomThreadExceptionHandlerAttached;
248248

249249
/// <summary>
250-
/// Gets the default dark mode for the application. This is the SystemColorMode which either has been set
251-
/// by <see cref="SetColorMode(SystemColorMode)"/> or its default value <see cref="SystemColorMode.Classic"/>.
250+
/// Gets the default color mode (dark mode) for the application.
252251
/// </summary>
252+
/// <remarks>
253+
/// <para>
254+
/// This is the <see cref="SystemColorMode"/> which either has been set by <see cref="SetColorMode(SystemColorMode)"/>
255+
/// or its default value <see cref="SystemColorMode.Classic"/>. If it has been set to <see cref="SystemColorMode.System"/>,
256+
/// then the actual color mode is determined by the system settings (which can be retrieved by the
257+
/// static (shared in VB) <see cref="Application.SystemColorMode"/> property.
258+
/// </para>
259+
/// </remarks>
253260
[Experimental(DiagnosticIDs.ExperimentalDarkMode, UrlFormat = DiagnosticIDs.UrlFormat)]
254261
public static SystemColorMode ColorMode =>
255-
!s_systemColorMode.HasValue
256-
? SystemColorMode.Classic
257-
: s_systemColorMode.Value == SystemColorMode.System
258-
? SystemColorMode
259-
: s_systemColorMode.Value;
262+
s_colorMode ?? SystemColorMode.Classic;
260263

261264
/// <summary>
262-
/// Sets the default dark mode for the application.
265+
/// Sets the default color mode (dark mode) for the application.
263266
/// </summary>
264-
/// <param name="systemColorMode">The default dark mode to set.</param>
267+
/// <param name="systemColorMode">The application's default color mode (dark mode) to set.</param>
268+
/// <remarks>
269+
/// <para>
270+
/// You should use this method to set the default color mode (dark mode) for the application. Set it,
271+
/// before creating any UI elements, to ensure that the correct color mode is used. You can set it to
272+
/// dark mode (<see cref="SystemColorMode.Dark"/>), light mode (<see cref="SystemColorMode.Classic"/>)
273+
/// or to the system setting (<see cref="SystemColorMode.System"/>).
274+
/// </para>
275+
/// <para>
276+
/// If you set it to <see cref="SystemColorMode.System"/>, the actual color mode is determined by the
277+
/// Windows system settings. If the system setting is changed, the application will not automatically
278+
/// adapt to the new setting.
279+
/// </para>
280+
/// <para>
281+
/// Note that the dark color mode is only available from Windows 11 on or later versions. If the system
282+
/// is set to a high contrast mode, the dark mode is not available.
283+
/// </para>
284+
/// <para>
285+
/// <b>Note for Visual Basic:</b> If you are using the Visual Basic Application Framework, you should set the
286+
/// color mode by handling the Application Events (see "WindowsFormsApplicationBase.ApplyApplicationDefaults").
287+
/// </para>
288+
/// </remarks>
265289
[Experimental(DiagnosticIDs.ExperimentalDarkMode, UrlFormat = DiagnosticIDs.UrlFormat)]
266290
public static void SetColorMode(SystemColorMode systemColorMode)
267291
{
268292
try
269293
{
270-
// Can't use the Generator here, since it cannot deal with experimentals.
294+
// Can't use the Generator here, since it cannot deal with [Experimental].
271295
_ = systemColorMode switch
272296
{
273297
SystemColorMode.Classic => systemColorMode,
@@ -276,18 +300,12 @@ public static void SetColorMode(SystemColorMode systemColorMode)
276300
_ => throw new ArgumentOutOfRangeException(nameof(systemColorMode))
277301
};
278302

279-
if (systemColorMode == s_systemColorMode)
303+
if (systemColorMode == s_colorMode)
280304
{
281305
return;
282306
}
283307

284-
if (GetSystemColorModeInternal() > -1)
285-
{
286-
s_systemColorMode = systemColorMode;
287-
return;
288-
}
289-
290-
s_systemColorMode = SystemColorMode.Classic;
308+
s_colorMode = systemColorMode;
291309
}
292310
finally
293311
{
@@ -315,6 +333,7 @@ static void NotifySystemEventsOfColorChange()
315333
bool complete = false;
316334
bool success = PInvoke.SendMessageCallback(hwnd, PInvoke.WM_SYSCOLORCHANGE + MessageId.WM_REFLECT, () => complete = true);
317335
Debug.Assert(success);
336+
318337
if (!success)
319338
{
320339
return;
@@ -357,25 +376,21 @@ private static int GetSystemColorModeInternal()
357376
{
358377
if (SystemInformation.HighContrast)
359378
{
360-
return DarkModeNotAvailable;
379+
return SystemDarkModeDisabled;
361380
}
362381

363-
int systemColorMode = DarkModeNotAvailable;
382+
int systemColorMode = SystemDarkModeDisabled;
364383

365-
// Dark mode is supported when we are >= W11/22000
366-
// Technically, we could go earlier, but then the APIs we're using weren't officially public.
367-
if (OsVersion.IsWindows11_OrGreater())
384+
try
385+
{
386+
// 0 for dark mode and |1| for light mode.
387+
systemColorMode = Math.Abs((Registry.GetValue(
388+
keyName: DarkModeKeyPath,
389+
valueName: DarkModeKey,
390+
defaultValue: SystemDarkModeDisabled) as int?) ?? systemColorMode);
391+
}
392+
catch (Exception ex) when (!ex.IsCriticalException())
368393
{
369-
try
370-
{
371-
systemColorMode = (Registry.GetValue(
372-
keyName: DarkModeKeyPath,
373-
valueName: DarkModeKey,
374-
defaultValue: DarkModeNotAvailable) as int?) ?? systemColorMode;
375-
}
376-
catch (Exception ex) when (!ex.IsCriticalException())
377-
{
378-
}
379394
}
380395

381396
return systemColorMode;
@@ -388,7 +403,8 @@ private static int GetSystemColorModeInternal()
388403
[Experimental(DiagnosticIDs.ExperimentalDarkMode, UrlFormat = DiagnosticIDs.UrlFormat)]
389404
public static bool IsDarkModeEnabled =>
390405
!SystemInformation.HighContrast
391-
&& (ColorMode == SystemColorMode.Dark);
406+
&& (ColorMode == SystemColorMode.Dark
407+
|| (ColorMode == SystemColorMode.System && SystemColorMode == SystemColorMode.Dark));
392408

393409
/// <summary>
394410
/// Gets the path for the executable file that started the application.

0 commit comments

Comments
 (0)