Wednesday, April 23, 2008

Applying XP visual styles to Windows Forms applications

It looks ridiculous but your programs on such modern Microsoft's technology as .NET Windows Forms by default will look like old-sytle Win32 API application. Nobody (even inside Microsoft I think) can tell why the Windows Forms controls don't use Windows XP themes whenever it is possible.

However it is not so bad as it could be. Microsoft allows to include XP themes support into your project using one of the following ways:

  • Through adding a manifest file into your project. Here is a MSDN Article which describes this way;
  • Through Application.EnableVisualStyles() method call - much more simple but sometimes buggy in .NET 1.1;
Personally I prefer the second way especially after Microsoft proposed a workaround for the bug with EnableVisualStyles() method on .NET 1.1.

So, to enable XP styles in your Windows Forms application you just should to place Application.EnableVisualStyles() call in your project's main() procedure and make an additional Application.DoEvents() call to fix the possible problems in .NET 1.1. 
That is all? Not exactly.

If you simply placed your controls on the forms from Toolbox then most of buttons, checkboxes and other "button-like" controls will still have old look even if you call EnableVisualStyles() at the begining of your program. 
Why? Because all those components have FlatStyle property equal to Standard value by default while it should be set to System value.

So we need to run through all controls on each form and set its FlastStyle property to FlatStyle.System. To simplify all described tasks we have wrotten special XPStyle class which contains several static methods. Using these methods you can easily add XP styles support into your existing Windows Forms program.

 
using System;
using System.Windows.Forms;

namespace Korzh.EasyQuery.ModelEditor
{
 /// 
 /// Represents different procedures that allows to turn on XP visual style for Windows Forms application
 /// 
 public class XPStyle
 {
        /// 
        /// Gets a value indicating whether XP themes feature is present.
        /// 
        /// true if XP themes feature is present; otherwise, false.
  public static bool IsXPThemesPresent {
   get { return OSFeature.Feature.IsPresent(OSFeature.Themes); }
  }

        /// 
        /// Enables the visual styles for application.
        /// 
  public static void EnableVisualStyles() {
            if (!IsXPThemesPresent) return;
   Application.EnableVisualStyles();
   Application.DoEvents();  
  }

        /// 
        /// Applies the visual styles for some control.
        /// 
        /// The control.
  public static void ApplyVisualStyles(Control control) {
            if (!IsXPThemesPresent) return;
   ChangeControlFlatStyleToSystem(control);
  }

  private static void ChangeControlFlatStyleToSystem(Control control) {
   // If the control derives from ButtonBase, 
   // set its FlatStyle property to FlatStyle.System.
   if(control.GetType().BaseType == typeof(ButtonBase)) {
    ((ButtonBase)control).FlatStyle = FlatStyle.System; 
   }

   // If the control holds other controls, iterate through them also.
   for(int i = 0; i < control.Controls.Count; i++) {
    ChangeControlFlatStyleToSystem(control.Controls[i]);
   }
  }

 }
}

Now you should call EnableVisualStyles() method of this class at the begining of your program and then call ApplyVisualStyles() for each form (at the end of form's constructor or in Load event handler).
 
 .  .  .  .  .  .  .  
 static void Main(string[] args) {
  XpStyle.EnableVisualStyles();

  Application.Run(new MainForm());
 }
 .  .  .  .  .  .  .  


 .  .  .  .  .  .  .  

 private void MainForm_Load(object sender, System.EventArgs e) {
  XPStyle.ApplyVisualStyles(this);
 }