Theming in a universal app

For Windows Phone Silverlight Apps it can he hard to do theming / branding in your app. Lucky Jeff Wilcox created the Theme Manager which easily let us control the Dark / Light theme and the accent color.

Windows Phone Store Apps

For Windows Phone Store apps we can’t use that ThemeManager but switching between Dark and light theme is now building in the framework like windows store apps have. The only thing we need to set:

RequestTheme=”Dark” or RequestTheme=”Light”

We can do this for the whole app or at an page / control. All child controls will get the specified theme. This makes it even easy to combine the light and dark theme.

When we are branding an application we not only want to set the theme but also want to set the accent color. This accent color is used by different controls. For example a textbox border.  When it’s having the focus the border is colored in the accent color. This is the part where it gets hard. There is no real easy way to do this. In Silverlight apps you can use the ThemeManager but for Phone Store apps no real good solution.

Microsoft advices to use SystemColorControlAccentColor and SystemColorControlAccentBrush style keys to use in your xaml to refer to the phone accent color. In Windows this color will always return a blue color. I tried to update the value of this system color / brush but unfortunately that isn’t working. So I opened generic.xaml (C:\Program Files (x86)\Windows Phone Kits\8.1\Include\abi\Xaml\Design\generic.xaml). In this file all default control styles are defined. I took a look and I found 28 styles that are using the SystemColorControlAccentColor.

  • PhoneHighContrastSelectedForegroundThemeBrush

  • JumpListDefaultEnabledBackground

  • ListPickerFlyoutPresenterSelectedItemForegroundThemeBrush

  • ProgressBarBackgroundThemeBrush

  • PhoneAccentBrush

  • PhoneRadioCheckBoxPressedBrush

  • TextSelectionHighlightColorThemeBrush

  • ButtonPressedBackgroundThemeBrush

  • CheckBoxPressedBackgroundThemeBrush

  • ComboBoxHighlightedBorderThemeBrush

  • ComboBoxItemSelectedForegroundThemeBrush

  • ComboBoxPressedBackgroundThemeBrush

  • HyperlinkPressedForegroundThemeBrush

  • ListBoxItemSelectedBackgroundThemeBrush

  • ListBoxItemSelectedPointerOverBackgroundThemeBrush

  • ListViewItemCheckHintThemeBrush

  • ListViewItemCheckSelectingThemeBrush

  • ListViewItemDragBackgroundThemeBrush

  • ListViewItemSelectedBackgroundThemeBrush

  • ListViewItemSelectedPointerOverBackgroundThemeBrush

  • ListViewItemSelectedPointerOverBorderThemeBrush

  • ProgressBarForegroundThemeBrush

  • ProgressBarIndeterminateForegroundThemeBrush

  • SliderTrackDecreaseBackgroundThemeBrush

  • SliderTrackDecreasePointerOverBackgroundThemeBrush

  • SliderTrackDecreasePressedBackgroundThemeBrush

  • ToggleSwitchCurtainBackgroundThemeBrush

  • ToggleSwitchCurtainPointerOverBackgroundThemeBrush

  • ToggleSwitchCurtainPressedBackgroundThemeBrush

  • LoopingSelectorSelectionBackgroundThemeBrush

When updating all these styles will it does the trick and you are no longer seeing the system accent color in your application but the color you defined.

Then the statusbar, this  won’t change when you update the styles as mentioned here above. When using the light theme the icons will even become invisible if you dont do anything. The icons stay white and your application has a white background. You can easily fix this by setting:

var statusBar = StatusBar.GetForCurrentView();
statusBar.ForegroundColor = color;
 

The only real limition now is the ProgressIndictor that is integrated with the statusbar, there is no way to change the color of it.

 

Windows Store apps

The dark/light theme is always choosen by the application and never by the user (or you have to built something in the application for this). The accent color isn’t really often used by the standard controls. So it won't be very visible when you don’t change it. But when you want to make it really nice you can change it here; you will get the TextSelectionColor then in your theme and at a few other places it becomes visible.  There are 8 styles you have to update.

  • ComboBoxItemSelectedBackgroundThemeBrush

  • ComboBoxSelectedBackgroundThemeBrush

  • IMECandidateSelectedBackgroundThemeBrush

  • ListBoxItemSelectedBackgroundThemeBrush

  • ListViewItemSelectedBackgroundThemeBrush

  • SearchBoxButtonBackgroundThemeBrush

  • SearchBoxHitHighlightForegroundThemeBrush

  • TextSelectionHighlightColorThemeBrush

Now to make this reusable across different projects I maked a class that manages this for me. First add this class:

public static class ThemeManager
    {
        private static readonly string[] brushKeys = new[]
        {
            //wp
            "PhoneHighContrastSelectedForegroundThemeBrush",
            "JumpListDefaultEnabledBackground","ListPickerFlyoutPresenterSelectedItemForegroundThemeBrush",
            "ProgressBarBackgroundThemeBrush",
            "PhoneAccentBrush",
            "PhoneRadioCheckBoxPressedBrush",
            "TextSelectionHighlightColorThemeBrush",
            "ButtonPressedBackgroundThemeBrush",
            "CheckBoxPressedBackgroundThemeBrush",
            "ComboBoxHighlightedBorderThemeBrush",
            "ComboBoxItemSelectedForegroundThemeBrush",
            "ComboBoxPressedBackgroundThemeBrush",
            "HyperlinkPressedForegroundThemeBrush",
            "ListBoxItemSelectedBackgroundThemeBrush",
            "ListBoxItemSelectedPointerOverBackgroundThemeBrush",
            "ListViewItemCheckHintThemeBrush",
            "ListViewItemCheckSelectingThemeBrush",
            "ListViewItemDragBackgroundThemeBrush",
            "ListViewItemSelectedBackgroundThemeBrush",
            "ListViewItemSelectedPointerOverBackgroundThemeBrush",
            "ListViewItemSelectedPointerOverBorderThemeBrush",
            "ProgressBarForegroundThemeBrush",
            "ProgressBarIndeterminateForegroundThemeBrush",
            "SliderTrackDecreaseBackgroundThemeBrush",
            "SliderTrackDecreasePointerOverBackgroundThemeBrush",
            "SliderTrackDecreasePressedBackgroundThemeBrush",
            "ToggleSwitchCurtainBackgroundThemeBrush",
            "ToggleSwitchCurtainPointerOverBackgroundThemeBrush",
            "ToggleSwitchCurtainPressedBackgroundThemeBrush",
            "LoopingSelectorSelectionBackgroundThemeBrush",
 
            // windows
            "ComboBoxItemSelectedBackgroundThemeBrush",
            "ComboBoxSelectedBackgroundThemeBrush",
            "IMECandidateSelectedBackgroundThemeBrush",
            "ListBoxItemSelectedBackgroundThemeBrush",
            "ListViewItemSelectedBackgroundThemeBrush",
            "SearchBoxButtonBackgroundThemeBrush",
            "SearchBoxHitHighlightForegroundThemeBrush",
            "TextSelectionHighlightColorThemeBrush",
 
        };
 
 
        public static void SetThemeColor(Color color)
        {
            foreach (var brushKey in brushKeys)
            {
                if (Application.Current.Resources.ContainsKey(brushKey))
                {
                    var solidColorBrush = Application.Current.Resources[brushKey] as SolidColorBrush;
                    if (solidColorBrush != null)
                        solidColorBrush.Color = color;
                }
            }
 
#if WINDOWS_PHONE_APP
            var statusBar = StatusBar.GetForCurrentView();
            statusBar.ForegroundColor = color;
#endif

}

}

Then in your app.xaml add this, make sure you have a theme color for all themes:

<Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.ThemeDictionaries>
                <ResourceDictionary x:Key="Dark">
                    <Color x:Key="ThemeColor">#851FFF</Color>
                    <SolidColorBrush x:Key="ThemeBrush" Color="{ThemeResource ThemeColor}" />
                </ResourceDictionary>
                <ResourceDictionary x:Key="Light">
                    <Color x:Key="ThemeColor">#851FFF</Color>
                    <SolidColorBrush x:Key="ThemeBrush" Color="{StaticResource ThemeColor}" />
                </ResourceDictionary>
            </ResourceDictionary.ThemeDictionaries>
        </ResourceDictionary>
    </Application.Resources>

 

Override the OnWindowCreated method in the app.xaml.cs and active the ThemeManager:

protected override void OnWindowCreated(WindowCreatedEventArgs args)
        {
            ThemeManager.SetThemeColor((Color)Resources["ThemeColor"]);
            base.OnWindowCreated(args);
        }

 

Hope it’s useful for you. I also added the ThemeManager in a NuGet package, but don’t forget to add the resource dictionaries in your app.xaml.cs

Make sure you dont try to assign the color directly in code. Without the resource dictionary in your app.xaml the ThemeManager won't  find any styles to update for an unclear reason.

Install-Package DaveSmits.ThemeManager