Themes and Skins

Introduction

Themes in PRADO provide a way for developers to provide a consistent look-and-feel across an entire web application. A theme contains a list of initial values for properties of various control types. When applying a theme to a page, all controls on that page will receive the corresponding initial property values from the theme. This allows themes to interact with the rich property sets of the various PRADO controls, meaning that themes can be used to specify a large range of presentational properties that other theming methods (e.g. CSS) cannot. For example, themes could be used to specify the default page size of all data grids across an application by specifying a default value for the PageSize property of the TDataGrid control.

Understanding Themes

A theme is a directory that consists of skin files, javascript files and CSS files. Any javascript or CSS files contained in a theme will be registered with the page that the theme is applied to. A skin is a set of initial property values for a particular control type. A control type may have one or several skins, each identified by a unique SkinID. When applying a theme to a page, a skin is applied to a control if the control type and the SkinID value both match to those of the skin. Note, if a skin has an empty SkinID value, it will apply to all controls of the particular type whose SkinID is not set or empty. A skin file consists of one or several skins, for one or several control types. A theme is the union of skins defined in all skin files.

Using Themes

To use a theme, you need to set the Theme property of the page with the theme name, which is the theme directory name. You may set it in either page configurations or in the constructor or onPreInit() method of the page. You cannot set the property after onPreInit() because by that time, child controls of the page are already created (skins must be applied to controls right after they are created.)

To use a particular skin in the theme for a control, set SkinID property of the control in template like following,

<com:TButton SkinID="Blue" ... />

This will apply the 'Blue' skin to the button. Note, the initial property values specified by the 'Blue' skin will overwrite any existing property values of the button. Use stylesheet theme if you do not want them to be overwritten. To use stylesheet theme, set the StyleSheetTheme property of the page instead of Theme (you can have both StyleSheetTheme and Theme).

To use the Javascript files and CSS files contained in a theme, a THead control must be placed on the page template. This is because the theme will register those files with the page and THead is the right place to load those files.

It is possible to specify media types of CSS files contained in a theme. By default, a CSS file applies to all media types. If the CSS file is named like mystyle.print.css, it will be applied only to print media type. As another example, mystyle.screen.css applies to screen media only, and mystyle.css applies to all media types.

Theme Storage

All themes by default must be placed under the [AppEntryPath]/themes directory, where AppEntryPath refers to the directory containing the application entry script. If you want to use a different directory, configure the BasePath and BaseUrl properties of the System.Web.UI.TThemeManager module in application configuration,

<service id="page" class="TPageService">
    <modules>
        <module id="theme"
                class="System.Web.UI.TThemeManager"
                BasePath="mythemes"
                BaseUrl="mythemes" />
    </modules>
</service>

Creating Themes

Creating a theme involves creating the theme directory and writing skin files (and possibly Javascript and CSS files). The name of skin files must be terminated with .skin. The format of skin files are the same as that of control template files. Since skin files do not define parent-child presentational relationship among controls, you cannot place a component tag within another. And any static texts between component tags are discarded. To define the aforementioned 'Blue' skin for TButton, write the following in a skin file,

<com:TButton SkinID="Blue" BackColor="blue" />

As aforementioned, you can put several skins within a single skin file, or split them into several files. A commonly used strategy is that each skin file only contains skins for one type of controls. For example, Button.skin would contain skins only for the TButton control type.

Web controls decorators

Available from Prado versions 3.2a onwards.

As an alternative to the previous methods, to customize the rending of a control its Decorator property can be customized. A TWebControlDecorator can add custom text (html code) before and after both the open and close tag of the control.

<com:THeader3>
    <prop:Decorator.PreTagText>
            <!-- Surround the control with a div and apply a css class to it -->
        <div class="imported-theme-h3-container">
    </prop:Decorator.PreTagText>
    <prop:Decorator.PostTagText>
            <!-- Properly close the tag -->
        </div>
    </prop:Decorator.PostTagText>
    My Nice Title
</com:THeader3>

In this example, a container div will be rendered around the THeader3 control, allowing the user to specify a css class for the container. TWebControlDecorator can also interpret prado's template code and output the resulting html:

<com:TPanel>
    <prop:Decorator.PreTagTemplate>
        <!-- Insert an header before the panel -->
        <com:THeader3>
            Panel's Injected Title
        </com:THeader3>
    </prop:Decorator.PreTagTemplate>
    <prop:Decorator.PostTagTemplate>
            <!-- Insert a date picker after the panel -->
        Pick a date: <com:TDatePicker />
    </prop:Decorator.PostTagTemplate>
    Panel contents here.
</com:TPanel>

Note that you can use the Decorator property also inside skin files, getting it applied automatically to all the controls subjected to the specific skin.