Custom themes and dynamic UI styles for UWP app

DotNET Fan 191 Reputation points
2024-09-02T06:01:10.4966667+00:00

Hello UWP experts ,

We have 6 resource dictionaries having different themes , particulary app background, button colors etc...

And initially from the application resources it loads the default one if user didn't select any other theme.

<Application.Resources>
      <ResourceDictionary>
             <ResourceDictionary.MergedDictionaries>  
             <ResourceDictionary Source="ms-appx:///Themes/default.xaml" />
         </ResourceDictionary.MergedDictionaries>
     </ResourceDictionary>
 </Application.Resources> 

We have a content dialog where user can select a particular theme of their choice and the code will select the particular resource dictionary having that theme and loads the button colors and other background. But unfortunately UI is not getting updated with the background colors,styles and the application is crashing.

The resource dictionary has the same filename as the theme name and this is how it loads a particular theme xaml dynamically and it is done in

app.xaml.cs

 var skinDictionary = new ResourceDictionary();
             skinDictionary.Source = new Uri($"ms-appx:///Themes/{theme}.xaml", UriKind.Absolute);
             Application.Current.Resources.MergedDictionaries.Clear();
             Application.Current.Resources.MergedDictionaries.Add(skinDictionary);

The resource dictionary has button styles set with the key defined <Style TargetType="Button" x:Key="AppButtonStyle"> and it is being referred in button as Style="{ThemeResource AppButtonStyle}"

Also there are other windows created through a new dispatcher thread and the page uses the theme resources - for eg:

CoreApplicationView newView = CoreApplication.CreateNewView();
 int newViewId = 0;
 await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
 {
     Frame frame = new Frame();
     frame.Navigate(typeof(NewPage));
}

What is the best approach to update the UI on the fly for custom themes defined in different resource dictionaries for these cases?

Universal Windows Platform (UWP)
{count} votes

1 answer

Sort by: Most helpful
  1. Junjie Zhu - MSFT 17,401 Reputation points Microsoft Vendor
    2024-09-10T06:40:35.1766667+00:00

    Hi @DotNET Fan ,

    Welcome to Microsoft Q&A!

    Currently, UWP does not have an API to effectively switch resource files on the code side. As a workaround, it is recommended that you use Application.Current.Resources.MergedDictionaries to read specific keys and modify the value.

    App.xaml

    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                    <Color x:Key="PrimaryColor">Blue</Color>
                    <Color x:Key="SecondaryColor">SkyBlue</Color>
                    <SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource PrimaryColor}" />
                    <SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource SecondaryColor}" />
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
    

    MainPage.xaml

    <Grid Background="{StaticResource PrimaryBrush }"  >
        <Button Background="{StaticResource SecondaryBrush}" Width="100" Height="100" HorizontalAlignment="Center" VerticalAlignment="Center" CornerRadius="4">Click Me</Button>
        <StackPanel Orientation="Vertical" Padding="10" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0 0 0 20">
            <RadioButton Content="Bluish" Tapped="RadioButton_Tapped"></RadioButton>
            <RadioButton Content="Reddish" Tapped="RadioButton_Tapped_1"></RadioButton>
        </StackPanel>
    </Grid>
    

    MainPage.xaml.cs

    private void RadioButton_Tapped(object sender, TappedRoutedEventArgs e)
    {
        //SetTheme("bluish");
        if (Application.Current.Resources.MergedDictionaries[0].ContainsKey("PrimaryBrush"))
        {
            var brush = Application.Current.Resources.MergedDictionaries[0]["PrimaryBrush"] as SolidColorBrush;
            if (brush != null)
            {
                brush.Color = Colors.Blue;
            }
        }
        if (Application.Current.Resources.MergedDictionaries[0].ContainsKey("SecondaryBrush"))
        {
            var brush = Application.Current.Resources.MergedDictionaries[0]["SecondaryBrush"] as SolidColorBrush;
            if (brush != null)
            {
                brush.Color = Colors.SkyBlue;
            }
        }
    }
    private void RadioButton_Tapped_1(object sender, TappedRoutedEventArgs e)
    {
        //SetTheme("reddish");
        if (Application.Current.Resources.MergedDictionaries[0].ContainsKey("PrimaryBrush"))
        {
            var brush = Application.Current.Resources.MergedDictionaries[0]["PrimaryBrush"] as SolidColorBrush;
            if (brush != null)
            {
                brush.Color = Colors.Red;
            }
        }
        if (Application.Current.Resources.MergedDictionaries[0].ContainsKey("SecondaryBrush"))
        {
            var brush = Application.Current.Resources.MergedDictionaries[0]["SecondaryBrush"] as SolidColorBrush;
            if (brush != null)
            {
                brush.Color = Colors.Green;
            }
        }
    }
    

    Thank you.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.