Search code examples
c#uwpwin-universal-app

UWP RequestedTheme is not consistent in ListView and ListViewItem


My NowPlayFullPage has a PlaylistControl, which is basically a ListView.

<local:PlaylistControl
    x:Name="FullPlaylistControl"
    Margin="10,10,10,0"
    AllowReorder="True"
    AlternatingRowColor="False"
    Background="Transparent"
    IsNowPlaying="True"
    RequestedTheme="Dark" />

The ItemTemplate of the PlaylistControl is the following:

<local:PlaylistControlItem
    Data="{x:Bind}"
    DataContext="{x:Bind}"
    RequestedTheme="{Binding ElementName=PlaylistController, Path=RequestedTheme}"
    ShowAlbumText="{Binding ElementName=PlaylistController, Path=ShowAlbumText}" />

And in the Loaded event of the PlaylistControlItem, I called a function SetTextColor

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    MediaHelper.SwitchMusicListeners.Add(this);
    SetTextColor(MediaHelper.CurrentMusic);
}

public void SetTextColor(Music music)
{
    if (Data == music)
    {
        TitleTextBlock.Foreground = ArtistTextButton.Foreground = AlbumTextButton.Foreground = DurationTextBlock.Foreground =
        LongArtistTextButton.Foreground = LongArtistAlbumPanelDot.Foreground = LongAlbumTextButton.Foreground = ColorHelper.HighlightBrush;
        TextColorChanged = true;
    }
    else if (TextColorChanged)
    {
        if (RequestedTheme == ElementTheme.Dark)
        {
            TitleTextBlock.Foreground = ColorHelper.WhiteBrush;
            ArtistTextButton.Foreground = AlbumTextButton.Foreground = DurationTextBlock.Foreground =
            LongArtistTextButton.Foreground = LongArtistAlbumPanelDot.Foreground = LongAlbumTextButton.Foreground = ColorHelper.GrayBrush;
        }
        else
        {
            TitleTextBlock.Foreground = ArtistTextButton.Foreground = AlbumTextButton.Foreground = DurationTextBlock.Foreground =
            LongArtistTextButton.Foreground = LongArtistAlbumPanelDot.Foreground = LongAlbumTextButton.Foreground = ColorHelper.BlackBrush;
        }
        TextColorChanged = false;
    }
}

My question is, why does the RequestedTheme in the SetTextColor called in the Loaded event have the value of ElementTheme.Default instead of ElementTheme.Dark? When does the RequestTheme of PlaylistControlItem hold the value of Dark so that my text color can be set correctly?


Solution

  • Advisably you should he handling this using ThemeResource's in XAML, not in code, see: https://learn.microsoft.com/en-us/windows/uwp/xaml-platform/themeresource-markup-extension

    But to answer your question this is expected behaviour. ElementTheme.Default simply means the element has not had it's theme overridden and is using the default app theme. The other two values mean the element has specifically had it's theme overridden. App.Current.RequestedTheme gives the application's actual theme. FrameworkElement.RequestedTheme will always have a value of Default unless you explicitly set it to something else on that specific element. All of it's children will still have the value Default.

    Note, you should compare against ActualTheme, not RequestedTheme, as a parent may have caused it to be using a different theme than the application if it's value is still ElementTheme.Default.

    A method like below might help you to get a proper value of Light/Dark.

    public static ElementTheme GetEffectiveTheme(FrameworkElement e)
    {
        if (e.ActualTheme == ElementTheme.Default)
            return App.Current.RequestedTheme == ApplicationTheme.Dark ? ElementTheme.Dark : ElementTheme.Light;
    
        return e.ActualTheme;
    }
    

    But also, just use ThemeResources. They automatically re-evaluate on Theme change, no need for any code or event listeners.