Lorsque l’on crée une application windows phone, il y a un point qui est très important à faire attention : le choix du thème système par l’utilisateur. En effet l’utilisateur à la possibilité de modifier :
- la couleur ‘accent’ : un choix entre 10 (voir 11 si le constructeur/opérateur a rajouté une couleur)
- le thème : sombre (blanc sur fond noir) ou clair (noir sur fond blanc) qui modifie à la fois la couleur du fond, la couleur des contrôles, du textes, etc…
Toutefois, on souhaite parfois ignorer le changement de thème, on souhaite toujours que notre application ait un fond noir avec des écritures blanches, même si l’utilisateur à choisi le thème clair. C’est notamment le choix que j’avais fait pour TVShow, mais des applications « natives » ont aussi fait ce choix comme pour l’application Mail par exemple.
Forcer le thème sous Windows Phone 7.0
Il est très facile de forcer le thème sous windows phone 7.0, il suffit de se rendre dans le répertoire :
%ProgramFiles(x86)%\Microsoft SDKs\Windows Phone\v7.0\Design
Vous y trouverez l’ensemble des fichiers ressources des différents thèmes :

Chaque répertoire contient deux fichiers : System.Windows.xaml et ThemeResources.xaml, le premier étant identique pour chaque sous thème et le second étant quasi identique mis à part la couleur PhoneAccentColor entre les différents thèmes sombres et les différents thèmes clairs
Ceci dit, on peut simplifier tout cela en supprimant les références à la couleur accent et en supprimant les ressources qui ne change pas entre les thèmes clairs et sombres comme la taille des textes, les polices, etc… :
<Thickness x:Key="PhoneTouchTargetOverhang">12</Thickness>
correspondant à la marge nécessaire pour un élément « touch » et comme la taille des polices, etc…
On peut donc ne garder que deux thèmes : Light et Dark (je n’ai fait que de supprimer les brosses et les couleurs accents) :
forceTheme
Pour les utiliser, on pourrait les mettre directement dans le fichier App.xaml de la façon suivante :
<Application.Resources>
<ResourceDictionary x:Key="styles">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dark.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Toutefois je le déconseille vivement, car si l’utilisateur à déjà un thème sombre à quoi bon perdre du temps et des resources à redéfinir les ressources inutilement.
Je conseillerais donc plutôt d’écrire dans le constructeur de la classe App
if(((Visibility)this.Resources["PhoneLightThemeVisibility"])==Visibility.Visible)
{
this.Resources.MergedDictionaries.Add(new Resource....)
}
ainsi, on ne redéfinit le thème seulement quand l’utilisateur à sélectionner le thème clair.
Attention toutefois, le fond d’une application n’est pas du Silverlight, il est forcément blanc avec un thème clair par exemple, donc si vous ne mettez pas d’images de fond, pensez au moins à forcer la couleur de fond de votre page.
Et sous mango ?
Bah sous mango, cela ne fonctionne pas…
Et effet, d’après Peter Torr, Program Manager dans l’équipe Windows Phone 7 Application Platform, la méthode que l’on utilisait jusqu’à maintenant était un bogue, et ce dernier a été corrigé depuis. Il propose toutefois deux alternatives :
Utilisez les styles implicites ajoutés à Silverlight 4, ou de mettre à jour les resources à la place de les remplacer de la façon suivante :
(App.Current.Resources["PhoneForegroundBrush"] as SolidColorBrush).Color = Colors.Red
Alors comme Peter Torr n’a jamais tort et que le tort tue, voilà donc une classe qui va vous permettre de forcer le thème de votre application, de plus comme tout es code-behind, nous aurons des meilleures performances qu’auparavant :
static public class ForceTheme
{
static public void ForceLightTheme(this Application application)
{
((SolidColorBrush)application.Resources["PhoneForegroundBrush"]).Color = Color.FromArgb(0xDE, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneBackgroundBrush"]).Color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneContrastForegroundBrush"]).Color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneContrastBackgroundBrush"]).Color = Color.FromArgb(0xDE, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneDisabledBrush"]).Color = Color.FromArgb(0x4D, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneTextCaretBrush"]).Color = Color.FromArgb(0xDE, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneTextBoxBrush"]).Color = Color.FromArgb(0x26, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneTextBoxForegroundBrush"]).Color = Color.FromArgb(0xDE, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneTextBoxEditBackgroundBrush"]).Color = Color.FromArgb(0x00, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneTextBoxEditBorderBrush"]).Color = Color.FromArgb(0xDE, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneTextBoxReadOnlyBrush"]).Color = Color.FromArgb(0x2E, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneSubtleBrush"]).Color = Color.FromArgb(0x66, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneTextBoxSelectionForegroundBrush"]).Color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneRadioCheckBoxBrush"]).Color = Color.FromArgb(0x26, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneRadioCheckBoxDisabledBrush"]).Color = Color.FromArgb(0x00, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneRadioCheckBoxCheckBrush"]).Color = Color.FromArgb(0xDE, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneRadioCheckBoxCheckDisabledBrush"]).Color = Color.FromArgb(0x4D, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneRadioCheckBoxPressedBrush"]).Color = Color.FromArgb(0x00, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneRadioCheckBoxPressedBorderBrush"]).Color = Color.FromArgb(0xDE, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneSemitransparentBrush"]).Color = Color.FromArgb(0xAA, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneChromeBrush"]).Color = Color.FromArgb(0xFF, 0xDD, 0xDD, 0xDD);
((SolidColorBrush)application.Resources["PhoneInactiveBrush"]).Color = Color.FromArgb(0x33, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneInverseInactiveBrush"]).Color = Color.FromArgb(0xFF, 0xE5, 0xE5, 0xE5);
((SolidColorBrush)application.Resources["PhoneInverseBackgroundBrush"]).Color = Color.FromArgb(0xFF, 0xDD, 0xDD, 0xDD);
((SolidColorBrush)application.Resources["PhoneBorderBrush"]).Color = Color.FromArgb(0x99, 0x00, 0x00, 0x00);
}
static public void ForceDarkTheme(this Application application)
{
((SolidColorBrush)application.Resources["PhoneForegroundBrush"]).Color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneBackgroundBrush"]).Color = Color.FromArgb(0xFF, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneContrastForegroundBrush"]).Color = Color.FromArgb(0xFF, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneContrastBackgroundBrush"]).Color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneDisabledBrush"]).Color = Color.FromArgb(0x66, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneTextCaretBrush"]).Color = Color.FromArgb(0xFF, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneTextBoxBrush"]).Color = Color.FromArgb(0xBF, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneTextBoxForegroundBrush"]).Color = Color.FromArgb(0xFF, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneTextBoxEditBackgroundBrush"]).Color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneTextBoxEditBorderBrush"]).Color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneTextBoxReadOnlyBrush"]).Color = Color.FromArgb(0x77, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneSubtleBrush"]).Color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneTextBoxSelectionForegroundBrush"]).Color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneRadioCheckBoxBrush"]).Color = Color.FromArgb(0xBF, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneRadioCheckBoxDisabledBrush"]).Color = Color.FromArgb(0x66, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneRadioCheckBoxCheckBrush"]).Color = Color.FromArgb(0xFF, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneRadioCheckBoxCheckDisabledBrush"]).Color = Color.FromArgb(0x66, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneRadioCheckBoxPressedBrush"]).Color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneRadioCheckBoxPressedBorderBrush"]).Color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneSemitransparentBrush"]).Color = Color.FromArgb(0xAA, 0x00, 0x00, 0x00);
((SolidColorBrush)application.Resources["PhoneChromeBrush"]).Color = Color.FromArgb(0xFF, 0x1F, 0x1F, 0x1F);
((SolidColorBrush)application.Resources["PhoneInactiveBrush"]).Color = Color.FromArgb(0x33, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneInverseInactiveBrush"]).Color = Color.FromArgb(0xFF, 0xCC, 0xCC, 0xCC);
((SolidColorBrush)application.Resources["PhoneInverseBackgroundBrush"]).Color = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
((SolidColorBrush)application.Resources["PhoneBorderBrush"]).Color = Color.FromArgb(0xBF, 0xFF, 0xFF, 0xFF);
}
}
Pour l’utiliser, il suffit d’ajouter la classe à votre application et d’écrire dans le constructeur de App :
this.ForceDarkTheme();
ou
this.ForceLightTheme();
selon votre souhait.
Attention encore une fois, le fond d’une application n’est pas du Silverlight, il est forcément blanc avec un thème clair par exemple, donc si vous ne mettez pas d’images de fond, pensez au moins à forcer la couleur de fond de votre page.
Conclusion
Niveau performance, on gagne sur l’ancienne solution, car pas de parsage xaml, toutefois attention, seuls les brush ont été redéfini, il est en effet impossible de redéfinir les Color, attention donc à bien utiliser les SolidBrush et non les Colors.
Enfin, n’hésitez pas à reprendre et adapter le code selon vos besoins et votre charte graphique !
ForceTheme Windows Phone 7
ForceTheme Windows Phone 7.1