Thursday, September 04, 2008

Organising Silverlight XAML Resources

I recently had to work through a large number of XAML files and rationalise the use of styles in a medium-size Silverlight application.

The original files had been produced with Expression Blend, and although some effort had been put into reusing common features such as fonts and colours, the resulting XAML was a mixture of named styles used as static resources and inline setting of properties. There was also repetition of styles across files within the project both in name and in content.

Styles with the same key within a resource hierarchy will override each other with the definition nearest the element winning out and it is easy, unintentionally, to quickly accumulate styles with the same contents but different keys unless you're careful.

An obvious inclination in this sort of situation is to centralise everything and to eliminate all duplication in order to tidy up things up. Styles and other resources used in more than one page or control can be placed in the App.xaml file of an application and accessed as static resources from XAML across the project. In this way if a change is required to the house style, like changing to a new standard font or colour-scheme, a single change in the central resources and a recompile is all that is required for the changes to apply throughout the entire project. And don't forget that one resource can make use of another; so, for example, a font name can be declared as a named resource and all other style resources can reference it as a static resource:

<Sys:String x:Key="HouseFont">
Verdana
</Sys:String>
<
Sys:String x:Key="BigTextSize">
56
</Sys:String>

<
Style x:Key="BigButtonStyle" TargetType="Button">
<
Setter Property="FontFamily" Value="{StaticResource HouseFont}" />
<
Setter Property="FontSize" Value="{StaticResource BigTextSize}" />
</
Style>


...


<Button Style="{StaticResource BigButtonStyle}" />



On the whole this works fine, and the really nice thing is that the resource management features in Expression Blend make using and maintaining the resources easy. When creating new styles in the designer you can opt to store them centrally and when editing styles or templates it is easy to apply previously saved resources and avoid adding ad hoc styling.



BlendResources



At the same time, however, it is important to bear in mind the intentions of the designer of the application's visuals - my first, over-rigorous attempts at eliminating duplication of styles where the property values were all the same led to some problems because I didn't realise that two styles with exactly the same contents could still be two different styles. Take this example, where two styles contain the same setters and values:



<Style x:Key="ProductDescriptionTextBlockStyle" TargetType="TextBlock">
<
Setter Property="FontFamily" Value="{StaticResource HouseFont}" />
<
Setter Property="FontSize" Value="{StaticResource MediumTextSize}" />
<
Setter Property="Foreground" Value="{StaticResource BrightTextColour}" />
<
Setter Property="TextWrapping" Value="NoWrap" />
</
Style>

<
Style x:Key="ThumbnailSubTitleTextBlockStyle" TargetType="TextBlock">
<
Setter Property="FontFamily" Value="{StaticResource HouseFont}" />
<
Setter Property="FontSize" Value="{StaticResource MediumTextSize}" />
<
Setter Property="Foreground" Value="{StaticResource BrightTextColour}" />
<
Setter Property="TextWrapping" Value="NoWrap" />
</
Style>



I first assumed these were obvious candidates for merging and renaming to a single style for use on product descriptions and thumbnail subtitles, but logically they are different, and to replace these two styles with a single generally named one locks the style of two conceptual different areas of the look and feel together artificially and arbitrarily - what if the designer of the UI later decides that thumbnail subtitles should be italicised? Would she expect all product descriptions to appear in italics? Rather obviously not. Clearly if a style is needed in more than one place because common aspects of visual design appear through the pages of an application then it makes sense to store it centrally in the application's resources and reference it everywhere it is needed, but elements that happen to have the same set of style properties but are not related to each other might have their styles stored centrally but they shouldn't have their styles merged arbitrarily.



So whilst it is important to rationalise repetition of genuinely duplicate style definitions, it is also important to realise that coincidence of content is not always equality of identity.



Another lesson I learnt was that over-centralisation could become cumbersome; I began by collecting styles in a grand sweep through the application and depositing them all in the App.xaml file on the general principle that styles stored centrally are available everywhere throughout the application if required. But what if they aren't required everywhere? What if styles are only of relevance to a particular page? As I progressed in my task I realised that general styles with names such as 'TitleTextBlock' occurred in several places with different setter content - moving them to a central location meant the need to rename them with prefixes to differentiate them and keep the compiler from objecting.



Under these circumstances it proved important to establish whether they needed to be held centrally at all - if they were only used in a particular page then it seemed better to leave them there and obviate the need for a prefix. On the other hand if they were used in several places and yet still had a conflicting name then a prefix seemed appropriate but adding a prefix based on the page where it was originally found before moving it into App.xaml led to confusing results - why was a style called 'BuyIt_TitleTextBlock' being used in the PrintDetails page? In these circumstances it was important to establish if the style was truly serving the the same purpose in all the locations it was being used and if so to give it a more accurate name that described its purpose rather than where it originated - in this case I settled on 'SummaryTitleTextBlock'.



Finally a word about the suffixes on style keys: as the names used in the style keys grew to include distinguishing qualifiers, their lengths became a bit unwieldy - 'ThumbnailSummaryTitleHyperlinkButtonStyle' for example, at 41 characters, is a getting bit long; and more importantly unnecessarily long - what actual useful information is conveyed by the inclusion of the 'HyperlinkButton' type when that is clear from the TargetType attribute in the declaration of the style? Similarly, the inclusion of the word 'Style' itself adds nothing that we don't already know - the fact is that either where the style is declared or where it is used, it will be clear to anyone reading the code, what it is and to which element type it applies. The only place where resources are seen 'out of context' as it were, is in the Resources view of Expression Blend and here a useful icon indicates the TargetType and the tooltip for each resource gives details of its type. As such it seemed reasonable to shorten resource keys to their descriptive parts with 'ThumbnailSummaryTitleHyperlinkButtonStyle' becoming merely 'ThumbnailSummaryTitle' - until I came up against two 'ThumbnailSummaryTitle' instances - one for a TextBlock and one for a HyperlinkButton in which case the reintroduction of the TargetType suffix was justified to distinguish the two styles.



 



Technorati Tags: ,,,

No comments: