Farr far away....

gary farr's blog
in

Better XAML By Farr: Compiled Resources in Application Development

One of the benefits of developing in WPF is the direct relation a developer and a designer now have.  A designer can create styles and templates in XAML and the developer can easily tie back end code into that XAML all while both access the same code base.  From a productivity value this is a huge win.  As a WPF developer I have been through the hardships of receiving pictures or even flash demos where my task was to make the application real.  Look, I know I am not a designer.  I have spent many hours sizing up pixels, working on layouts, and skinning/re-skinning applications.  However,  I want to make things work, not make them look pretty… 

That being said, even though I would like to work in the same environment as a designer and it makes overall development so much easier, there are some negative impacts.  Most application code base has a promotion process.  Different levels of testing environments before the code hits production.  The one problem with styling and developing within the same code base is that a change to one item would result in re-compilation of the other.  We still want to separate designer and developer responsibility even though we are in the same code base.  Basically, re-skinning an application should have no effect on the application logic.  For example, if a button color needs to be changed there is no reason why a recompilation of the event that button raises should occur.  Alternatively, if the event process is changed there is no reason the recompilation of the style should occur. 

One method of achieving this is through separating resources out into a separate project.  By doing so, you can have a design promotion process along with a development promotion process where neither process is dependent on the others code being re-compiled.   The style project contains all resources from layouts to animations.  The code project has a configuration parameter in its App.config file which points to the styles DLL.  In the example below I use a ConfigurationSection class in retrieving a configuration parameter pointing to a styles assembly.  

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:   <configSections>
   4:     <section name="AppSettings" type="App.Module.AppSettings, App.Module"/>
   5:   </configSections>
   6:   <AppSettings
   7:     StylesUri="pack://application:,,,/App.Module.Styles;component/MainResource.xaml"/>
   8: </configuration>

The above code in the App.Config file defines a configSection 'AppSettings’ of type App.Module.AppSettings in the assembly App.Module.  The attribute in AppSettings is a URI containing some WPF packaging text, the style assembly, and the Main Resource Dictionary within the compiled styles DLL.  I am assuming all styles in the project would be merged into a main resource dictionary for simplicity.  Please refer to Pack URIs in Windows Presentation Foundation for more information on creating Pack URIs for resources. 

   1: using System;
   2: using System.Configuration;
   3:  
   4: namespace App.Module.AppSettings
   5: {
   6:     public class AppSettings: ConfigurationSection
   7:     {
   8:         private static readonly AppSettings_settings = ConfigurationManager.GetSection("AppSettings") as AppSettings;
   9:  
  10:         public static AppSettingsSettings { get { return _settings; } }
  11:  
  12:         [ConfigurationProperty("StylesUri", IsRequired = true)]
  13:         public Uri StylesUri
  14:         {
  15:             get { return (Uri)this["StylesUri"]; }
  16:             set { this["StylesUri"] = value; }
  17:         }
  18:     }
  19: }

My ConfigurationSection class defines the Styles parameter I can then use in code.  One of the nice things about this class is that it enforces certain guidelines the attributes or elements in the AppSettings section in configuration must adhere to.  For example, the StylesUri property must be of type URI.  If you enter an integer for the StylesUri attribute in configuration, an exception will be thrown on loading of the application.  Also, since isRequired is set to true, an exception will also be thrown if that attribute is missing in configuration.  Again, the ConfigurationSection class enforces these rules so I do not have to write code against values in the configuration.

   1: //load resource dictionaries
   2: _view.Resources.MergedDictionaries.Add(new ResourceDictionary { Source = AppSettings.Settings.StylesUri });

Accessing the Configuration Section is quite easy as it is a singleton and can be accessed anywhere in the project.  The line of code above loads the StylesUri value into the view’s resources. 

In conclusion, there are several key benefits to external resources.  First, designers and developers can still work in the same environment and code base yet not have direct implications on each other’s code.  Second, from a developers perspective, this is a very clean implementation for handling styling within configuration.  I do not have to worry about validating configuration parameters which is a huge weight off my chest and I do not need any knowledge of what the resources my application is styled to.  Finally, this methodology introduces a really nice way for future re-styling without affecting the core code base.  Lets say six months from now the look and feel of the application needs to change from a summer design to a winter.  The core code base is never touched.  The designer can adjust the styles accordingly, compile and update the code project configuration StylesUri. 

Comments

No Comments

Leave a Comment

(required) 

(required) 

(optional)

(required)