0

I have three radio buttons for selecting my app's theme: Default, which should apply whichever theme is selected in Android's system settings, Light and Dark.

The problem is that whenever I select the Default radio button it doesn't return a standard value as I am expecting, but either OSAppTheme.Light or OSAppTheme.Dark, whichever the previous setting was. In other words it reapplies the previous setting.

Here is my code:

    private void DarkMode(object sender, CheckedChangedEventArgs e)
    {
        if (defaultRadioButton.IsChecked == true)
        {
            if (Application.Current.RequestedTheme != OSAppTheme.Unspecified)
            {
                Application.Current.UserAppTheme = Application.Current.RequestedTheme;
            }
            else
            {
                Application.Current.UserAppTheme = OSAppTheme.Light;
            }
        }
        else if (lightRadioButton.IsChecked == true)
        {
            Application.Current.UserAppTheme = OSAppTheme.Light;
        }
        else if (darkRadioButton.IsChecked == true)
        {
            Application.Current.UserAppTheme = OSAppTheme.Dark;
        }
     }

I had the impression that Application.Current.RequestedTheme always carried the system's setting, which I guess from the behavior I'm encountering isn't true.

If Application.Current.RequestedTheme doesn't get the system's theme setting, then which is the correct way to detect if a user has enabled Dark Mode at the OS level?

Costas
  • 459
  • 3
  • 15

1 Answers1

1

According to this case about Manually apply dark theme in Xamarin.Forms, the Application.Current.UserAppTheme only applys for the theme defined with AppThemeBinding.

So if you want to change the UI's theme with this property, you need to use the AppThemeBinding in your control such as the example code in the official document.

In addition, the Application.Current.RequestedTheme can really get the device's system's current theme. But you can also try to get the android device's current theme with the following code in the MainActivity:

var theme = this.Resources.Configuration.UiMode & Android.Content.Res.UiMode.NightMask;
//if the value is Android.Content.Res.UiMode.NightNo means the device is using light mode
//if the value is Android.Content.Res.UiMode.NightYes means the device is using dark mode

And then you can declare a dark theme in the Project.Droid/Resource/values/style.xml and use it or just use the AppThemeBinding as the official document does to apply the dark theme in your application.

Update

  1. Set the device's theme as dark
  2. Call the code above:
Application.Current.UserAppTheme = OSAppTheme.Light;
var theme = Application.Current.RequestedTheme;

The value will be dark. It should be a bug, you can report it on the github.

Liyun Zhang - MSFT
  • 8,271
  • 1
  • 2
  • 14
  • I'm using the `AppThemeBinding` with no issues. The only problem with the code I shared is that the `Application.Current.RequestedTheme` doesn't return a standard value, but it carries the value of the previously selected theme. – Costas Jan 18 '23 at 08:57
  • Anyway, I tried your line of code: `this.Resources.Configuration.UiMode & Android.Content.Res.UiMode.NightMask == Android.Content.Res.UiMode.NightNo` and I get the following error: `Error CS1061 'ResourceDictionary' does not contain a definition for 'Configuration' and no accessible extension method 'Configuration' accepting a first argument of type 'ResourceDictionary' could be found (are you missing a using directive or an assembly reference?)`. Is there a fix for it? – Costas Jan 18 '23 at 08:58
  • What does the standard value mean? I tested `Application.Current.RequestedTheme` and it will return `OSAppTheme.Light`. @Costas – Liyun Zhang - MSFT Jan 18 '23 at 09:01
  • Did you put the code `var theme = this.Resources.Configuration.UiMode & Android.Content.Res.UiMode.NightMask;` in the **android MainActivity**? @Costas – Liyun Zhang - MSFT Jan 18 '23 at 09:03
  • It means that if for example `Dark Mode` is enabled in the Android's settings, I would expect that it would always return `OSAppTheme.Dark`. That's not what happens though. If I have previously selected the `Light` radio button and then switch to the `Default` radio button it returns `OSAppTheme.Light`. As for the other code you suggested, my bad. I used it in the shared project, while that's for the Android one... – Costas Jan 18 '23 at 09:10
  • I can't reproduce the problem without the codes about the `radio button`, but according to the official document, the current system theme can be detected by getting the value of the `Application.RequestedTheme` property. You can try to report it as a bug on the github or try to update the xamarin.forms and xamarin essential to the last version. You can also use the code I provide to get the current theme on the android. @Costas – Liyun Zhang - MSFT Jan 18 '23 at 09:19
  • The related code is already posted. Do you also need the XAML code? – Costas Jan 18 '23 at 09:29
  • I tried to reproduce the problem: Set the device theme as dark -> select the light radio button -> select the default radio button and then the `Application.RequestedTheme` return dark. @Costas – Liyun Zhang - MSFT Jan 18 '23 at 09:45
  • I have tested again, and if you call `Application.Current.UserAppTheme = OSAppTheme.Light;` before the `Application.RequestedTheme`. It will return light. You can check the update part in my answer. @Costas – Liyun Zhang - MSFT Jan 18 '23 at 10:14
  • But why? Isn't `Application.RequestedTheme` supposed to carry the OS setting? And of course the OS setting isn't affected by `Application.Current.UserAppTheme`. – Costas Jan 18 '23 at 10:17
  • So I said it should be a bug, you can report it on the github. Or just try the code I provided to detect the system theme on the android. @Costas – Liyun Zhang - MSFT Jan 18 '23 at 10:21
  • Yeah, it probably is a bug... I guess it should be reported for it to get fixed. – Costas Jan 18 '23 at 10:25