Thursday, October 20, 2011

Apply Themes to WPF applications


NuGet command:
PM> Install-Package wpfthemes
As the WPF.Themes is built in Environment .Net 4.0, if we are building our application for .Net 4.0 above version, we can apply themes simply like below:
using WPF.Themes;     

namespace UseNuGetApplyThemes 
{          /// Interaction logic for MainWindow.xaml           public partial class MainWindow : Window     
      {         
          public MainWindow()         
         {             
             InitializeComponent();             
             this.ApplyTheme("WhistlerBlue");         
         }     
     } 
} 
The Themes names can be:
  • ExpressionDark
  • ExpressionLight
  • Rainier
  • RainierPurple
  • RainierOrange
  • RainierRadialBlue
  • Shiny
  • ShinyDarkGreen
  • ShinyDarkTeal
  • ShinyDarkPurple
  • ShinyBlue
  • ShinyRed
  • Bureau
  • BureauBlack
  • BureauBlue
  • Whistler
  • WhistlerBlue
  • DavesGlossyControls
  • DavesGlossyControls
  • UXMusing
  • UXMusingRed
  • UXMusingGreen
  • UXMusingRough
  • UXMusingRoughGreen
  • UXMusingRoughRed
  • UXMusingBubbly
  • UXMusingBubblyBlue
Let's use ILSpy to analyze the WPF.Themes.dll assembly, we w
ill see it use ThemeManager class extension method to apply themes, it is merge the theme to app resources dictionary, so if not .net 4.0 application, like .net 3.5, we can use its ThemeManager class, sometimes we don't want all the themes files included in the assemblies or use other themes not in the above list, we can use its method to apply themes too. Let's post it below:
using System;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
namespace WPF.Themes
{
 public static class ThemeManager
 {
  public static readonly DependencyProperty ThemeProperty = DependencyProperty.RegisterAttached("Theme", typeof(string), typeof(ThemeManager), new FrameworkPropertyMetadata(string.Empty, new PropertyChangedCallback(ThemeManager.OnThemeChanged)));
  public static ResourceDictionary GetThemeResourceDictionary(string theme)
  {
   ResourceDictionary result;
   if (theme != null)
   {
    Assembly assembly = Assembly.LoadFrom("WPF.Themes.dll");
    string uriString = string.Format("/WPF.Themes;component/{0}/Theme.xaml", theme);
    result = (Application.LoadComponent(new Uri(uriString, UriKind.Relative)) as ResourceDictionary);
   }
   else
   {
    result = null;
   }
   return result;
  }
  public static string[] GetThemes()
  {
   return new string[]
   {
    "ExpressionDark", 
    "ExpressionLight", 
    "ShinyBlue", 
    "ShinyRed", 
    "DavesGlossyControls", 
    "WhistlerBlue", 
    "BureauBlack", 
    "BureauBlue", 
    "BubbleCreme", 
    "TwilightBlue", 
    "UXMusingsRed", 
    "UXMusingsGreen", 
    "UXMusingsBubblyBlue"
   };
  }
  public static void ApplyTheme(this Application app, string theme)
  {
   ResourceDictionary themeResourceDictionary = ThemeManager.GetThemeResourceDictionary(theme);
   if (themeResourceDictionary != null)
   {
    app.Resources.MergedDictionaries.Clear();
    app.Resources.MergedDictionaries.Add(themeResourceDictionary);
   }
  }
  public static void ApplyTheme(this ContentControl control, string theme)
  {
   ResourceDictionary themeResourceDictionary = ThemeManager.GetThemeResourceDictionary(theme);
   if (themeResourceDictionary != null)
   {
    control.Resources.MergedDictionaries.Clear();
    control.Resources.MergedDictionaries.Add(themeResourceDictionary);
   }
  }
  public static string GetTheme(DependencyObject d)
  {
   return (string)d.GetValue(ThemeManager.ThemeProperty);
  }
  public static void SetTheme(DependencyObject d, string value)
  {
   d.SetValue(ThemeManager.ThemeProperty, value);
  }
  private static void OnThemeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  {
   string text = e.NewValue as string;
   if (!(text == string.Empty))
   {
    ContentControl contentControl = d as ContentControl;
    if (contentControl != null)
    {
     contentControl.ApplyTheme(text);
    }
   }
  }
 }
}

 

1 comment:

Unknown said...

Hey Jie

My name is Vedant (Vic) Sharma , Sr. recruiter with McgrawHill financial and I have a position of Software Engineer (.NET) developer position in NYC. I came across your profile in LinkedIn and Went through your blog. I am really impressed. i would appreciate if we can hold a conversation regarding the same. My e-mail id : vedant.sharma@adp.com and my contact number is 877-871-7364 extn 1034429. Thanks.