@@ -45,12 +45,12 @@ public sealed partial class Application
45
45
private static bool s_useWaitCursor ;
46
46
47
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.
48
- private static SystemColorMode ? s_systemColorMode ;
48
+ private static SystemColorMode ? s_colorMode ;
49
49
#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.
50
50
51
51
private const string DarkModeKeyPath = "HKEY_CURRENT_USER\\ SOFTWARE\\ Microsoft\\ Windows\\ CurrentVersion\\ Themes\\ Personalize" ;
52
52
private const string DarkModeKey = "AppsUseLightTheme" ;
53
- private const int DarkModeNotAvailable = - 1 ;
53
+ private const int SystemDarkModeDisabled = 1 ;
54
54
55
55
/// <summary>
56
56
/// Events the user can hook into
@@ -247,27 +247,51 @@ internal static bool CustomThreadExceptionHandlerAttached
247
247
=> ThreadContext . FromCurrent ( ) . CustomThreadExceptionHandlerAttached ;
248
248
249
249
/// <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.
252
251
/// </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>
253
260
[ Experimental ( DiagnosticIDs . ExperimentalDarkMode , UrlFormat = DiagnosticIDs . UrlFormat ) ]
254
261
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 ;
260
263
261
264
/// <summary>
262
- /// Sets the default dark mode for the application.
265
+ /// Sets the default color mode ( dark mode) for the application.
263
266
/// </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>
265
289
[ Experimental ( DiagnosticIDs . ExperimentalDarkMode , UrlFormat = DiagnosticIDs . UrlFormat ) ]
266
290
public static void SetColorMode ( SystemColorMode systemColorMode )
267
291
{
268
292
try
269
293
{
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] .
271
295
_ = systemColorMode switch
272
296
{
273
297
SystemColorMode . Classic => systemColorMode ,
@@ -276,18 +300,12 @@ public static void SetColorMode(SystemColorMode systemColorMode)
276
300
_ => throw new ArgumentOutOfRangeException ( nameof ( systemColorMode ) )
277
301
} ;
278
302
279
- if ( systemColorMode == s_systemColorMode )
303
+ if ( systemColorMode == s_colorMode )
280
304
{
281
305
return ;
282
306
}
283
307
284
- if ( GetSystemColorModeInternal ( ) > - 1 )
285
- {
286
- s_systemColorMode = systemColorMode ;
287
- return ;
288
- }
289
-
290
- s_systemColorMode = SystemColorMode . Classic ;
308
+ s_colorMode = systemColorMode ;
291
309
}
292
310
finally
293
311
{
@@ -315,6 +333,7 @@ static void NotifySystemEventsOfColorChange()
315
333
bool complete = false ;
316
334
bool success = PInvoke . SendMessageCallback ( hwnd , PInvoke . WM_SYSCOLORCHANGE + MessageId . WM_REFLECT , ( ) => complete = true ) ;
317
335
Debug . Assert ( success ) ;
336
+
318
337
if ( ! success )
319
338
{
320
339
return ;
@@ -357,25 +376,21 @@ private static int GetSystemColorModeInternal()
357
376
{
358
377
if ( SystemInformation . HighContrast )
359
378
{
360
- return DarkModeNotAvailable ;
379
+ return SystemDarkModeDisabled ;
361
380
}
362
381
363
- int systemColorMode = DarkModeNotAvailable ;
382
+ int systemColorMode = SystemDarkModeDisabled ;
364
383
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 ( ) )
368
393
{
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
- }
379
394
}
380
395
381
396
return systemColorMode ;
@@ -388,7 +403,8 @@ private static int GetSystemColorModeInternal()
388
403
[ Experimental ( DiagnosticIDs . ExperimentalDarkMode , UrlFormat = DiagnosticIDs . UrlFormat ) ]
389
404
public static bool IsDarkModeEnabled =>
390
405
! SystemInformation . HighContrast
391
- && ( ColorMode == SystemColorMode . Dark ) ;
406
+ && ( ColorMode == SystemColorMode . Dark
407
+ || ( ColorMode == SystemColorMode . System && SystemColorMode == SystemColorMode . Dark ) ) ;
392
408
393
409
/// <summary>
394
410
/// Gets the path for the executable file that started the application.
0 commit comments