Understanding the theme.skin File


Microsoft introduced Themes in ASP.NET 2.0 as an easy way to assign style and other properties declaratively to ASP.NET server controls like DataGrid, GridView, Calendar, DropdownList, TextBox, etc. After implementing support for using themes in mojoPortal, I realized/discovered that it is really a bad idea to use themes to assign style properties such as colors, borders etc to controls. The reason it is a bad idea to use themes to style your controls is that when you do this the styles are rendered inline and repeated everywhere in the markup for the control which makes the markup very bulky and can hurt perfomance because your page is slower to load due to the heavy markup of inline styles. It is far better to style your controls only with CSS So after implementing support for use of themes, we did not make much use of them in mojoPortal for a long time.
Example of what not to do:
<asp:DropDownList runat="server" 
This will result in the control rendering with style="border-color:blue;border-style-solid;border-width:1px;" on every instance of the dropdown control. It would be far cleaner to just have it render a class='myclass"
and then have it one place in your CSS as 
.myclass { border-color:blue;border-style-solid;border-width:1px; }  
instead of rendering over and over everwhere that a DropDownList is used.  This is just a small example, the repeated inline styles adds even more bulk on more complex controls like GridView or Calendar. So we really do not want to use the theme.skin file to set style properties like that.

But There Are Some Very Good Uses of Themes              

Over time there emerged some other beneficial ways to use themes in cases where we want to configure things about the way we render markup. For example in some skins we used Nifty Corners for implementing rounded corners, but this required some extra markup to be rendered and we needed a way to disable that extra markup in skins where we were not using the Nifty Corners technique. So I implemented at the time a CornerRounderTop and CornerRounderBottom control that renders the extra markup needed to round the upper corners and lower corners respectively. These controls are included in most of the features of mojoPortal in order to support the Nifty Corners rounding technique. However in skins that don't use this technique you will see in the theme.skin file setting slike this:
<mp:CornerRounderTop runat="server" DoRounding="false" />
<mp:CornerRounderBottom runat="server" DoRounding="false" />
The DoRounding property is used internally to the control to tell it whether to render the extra markup or not. Really the CSS does the rounding, but the controls produce the markup that the CSS needs to do the corner rounding so it is just a switch to turn on or off the rendering of the extra markup.
For a long time this control of the CornerRounders was the only thing we were really using the theme.skin file for, but then when we decided to implement support for Artisteer, we needed a way to render the additional markup needed for Artisteer designs without rendering it in non-Artisteer designs. So again we implemented the support for alternate/additional rendering but using switches that could be configured from the theme.skin file. In fact over time different versions of Artisteer have needed the markup or css classes used to be different.
Artisteer 2.3 Skins have this in theme.skin to enable the extra markup and css classes:
<portal:mojoPanel runat="server" RenderArtisteer="true" />
<portal:ModuleTitleControl runat="server" RenderArtisteer="true" />
<portal:HeadingControl runat="server" RenderArtisteer="true" />
in Artisteer 2.3 (and older I guess) it used mixed case CSS classes, but in Artisteer 2.4 it changed to lower case, so skins created using Artisteer 2.4 to 2.6 need the settings like this:
<portal:mojoPanel runat="server" RenderArtisteer="true" UseLowerCaseArtisteerClasses="true" />
<portal:ModuleTitleControl runat="server" RenderArtisteer="true" UseLowerCaseArtisteerClasses="true" />
<portal:HeadingControl runat="server" RenderArtisteer="true" UseLowerCaseArtisteerClasses="true" />
when we implemented this we left the default as false in order to not break the older skins.
In Artisteer 3.0 (Currently in Beta) the CSS class names changed again so we implemented it also in a backward compatible way. Skins created using Artisteer 3 need this:
<portal:mojoPanel runat="server" RenderArtisteer="true" UseLowerCaseArtisteerClasses="true" />
<portal:ModuleTitleControl runat="server" RenderArtisteer="true" UseLowerCaseArtisteerClasses="true" UseH3ForSideHeader="true" UseArtisteer3="true" />
<portal:HeadingControl runat="server" RenderArtisteer="true" UseLowerCaseArtisteerClasses="true" UseArtisteer3="true" />
More recently we moved some existing settings for Menus and TreeView controls that we used to control from SiteMenu and PageMenu properties into the theme.skin file and also added a bunch of new properties to control various things such as what CSS classes are rendered in order to make menu configuration much more flexible. I'll be updating this article with a link once I write some documentation about Menu and TreeView configuration, but if you look in the theme.skin file of skins that ship in the latest mojoPortal you should get the idea of what is possible.
For developers, you can have multiple templates for any given server control but each must have a unique SkinID. You assign the SkinID to the server control instance to make it use the particular set of properties defined on the template with the corresponding SkinID within the theme.skin file. You can also have one template per server control that uses no SkinID and corresponding server controls that have no SkinID will use that template. For designers, you generally don't really get to choose the SkinIDs swince that is done by developers. It is possible for the SiteMenu and PageMenu controls because they expose a custom property that maps to the SkinID by default it is MenuSkinID="SiteMenu" on SiteMenu control and MenuSkinID="PageMenu" on the PageMenu control but you are allowed to override those. The only real case wher eit might be useful to override those is for PageMenu since you may have up to 3 instance of PageMenu in your layout.master file and you may wish to configure them differently.

Problems Under .NET 3.5 Medium Trust Hosting

As you have seen, we include the theme.skin file in the mojoPortal skin folder along with all the other files needed for a mojoPortal skin. This was actually tricky to accomplish because ASP.NET really wants the theme files to be under /App_Themes folder. We solved it by implementing a VirtualPathProvider. The runtime actually still thinks the file does come from under /App_Themes/Default folder but the VirtualPathProvider serves the file from the skin specific folder allowing us to keep all the skin related files in one place. Unfortunately VirtualPathProviders do not work under .NET 3.5 Medium Trust hosting. They fixed this in .NET 4 and it is reason enough to move to .NET 4 hosting if possible in my opinion. If your site uses only one skin, it is not much of a problem because you could copy your theme.skin file up to /App_Themes/Default. But it is a problem if you use more than one skin and they need different settings or if you are hosting multiple sites using different skins. Again this problem is avoided altogether by using .NET 4 hosting and the .NET 4 packages of mojoPortal.

Additional Resources

Last Updated 2011-04-05 by Joe Audette