In this installment of my “XAML Anti-Patterns” series, I will explore the concept of XAML Resources. Once again, it's a concept that's fundamentally solid and good, but like many things in the world of XAML, the concept can be overused and turn into a slow and unmanageable mess in a heartbeat. It has a serious impact on the size, readability, and maintainability of the XAML code you create. What's more, it has negative runtime implications as well.
What are XAML Resources?
In XAML, you can define objects directly, or you can define objects as resources. For instance, it's possible to define a control's color directly like this:
<TextBox Foreground="Red" />
This creates a TextBox with - wait for it - a red foreground color. This line of code is actually shorthand for a TextBox with a foreground color set to a Brush
object. In this case, it's a pre-defined solid color brush called Red
. So the whole set up is actually a composition of two objects. The long-hand syntax for the same control could have been something like this:
<TextBox>
<TextBox.Foreground>
<SolidColorBrush Color="Red" />
</TextBox.Foreground>
</TextBox>
Either way, you end up with an object that has its foreground color set to a specific color object. Although that's fine, it may be more desirable to create a more abstract definition of the color, so it can be used easily and consistently across the entire application. In that case, you could define the control like so:
<TextBox Foreground="{DynamicResource MyForeground}" />
This defines a control that doesn't directly set its color, but instead uses the DynamicResource
extension to redirect its property value to a resource defined somewhere else. The resource itself can be defined like this and be stored in a separate place, such as App.xaml:
<SolidColorBrush Color="Red" x:Key="MyForeground" />
Using this approach, you can now point all the controls (not just text boxes!) to this brush in a generic fashion. If you later decided to change the color, all you have to do is change that one resource, and voila, all the controls change color. In fact, you could perhaps swap out a whole set of color resources all at once, to provide a rudimentary theming mechanism. So this is a cool and desirable technique.
It's important to understand that this works with all kinds of constructs and objects in XAML. The XAML resource system stores objects (a brush in this case, but other objects are fine also) in a generic place, assigns them a name, and allows you to generically refer to these objects later. The same system can be used for very advanced objects, such as data source definitions, control templates, binding coveters, styles, and just about anything else you can imagine defining in XAML.
More Technical Detail
It's worth exploring some of the details of the XAML Resource system a bit further. In the example above, the Foreground
property isn't set directly, but instead the standard XAML extension syntax (the curly bracket syntax) invokes another object that provides the value. In this particular example, a DynamicResource
object is created and MyForeground
is passed to the object's constructor. (Or, more accurately, the name of the object is DynamicResourceExtension
, but the Extension suffix isn't used in XAML). The object can then use the resource name to retrieve the reference in question.
To do this, the resource is looked up according to well-defined rules. First, the system attempts to find the resource in the current element. Every element in WPF can define resources, therefore, this construct is legal and the resource can be defined locally:
<TextBox Foreground="{DynamicResource MyForeground}">
<TextBox.Resources>
<SolidColorBrush Color="Red" x:Key="MyForeground" />
</TextBox.Resources>
</TextBox>
Whether this makes sense or not is a completely different question. Most people would argue that the use of resources only makes sense if the resource is defined elsewhere. Therefore, you can probably dismiss this scenario and let the resource lookup system continue its journey, which now takes it to the hierarchical parent of the element in question. In other words, if the TextBox element is inside of another container, such as a Grid, the system now attempts to find the resource with the Grid. If it isn't found there either, the next parent is considered. For instance, if the Grid itself lives inside of a TabControl, the current TabItem is considered, then the TabControl itself, then its parent (such as another Grid), then the parent of that object, such as a Window, and so on, until the resource is either found, or the root UI element is reached.
If the resource still isn't found at a particular UI's root level, the search continues application-wide, which typically means that the resources defined in App.xaml are searched. Hopefully, it isn't defined directly in App.xaml (which would in itself be an Anti-Pattern, since App.xaml
files should never directly contain resources because it leads to a completely unmanageable mess), but App.xaml often refers to external Resource Dictionaries, which are considered to be merged into the global app resources. (By the way, all resource definitions can merge dictionaries, which would be one reason the TextBox could hold an appropriate resource directly. But this is hardly ever done in the real world.) Due to this merging, there are usually a large number of global resources available that can be searched. Finally, if the resource isn't found there either, pre-defined system resources are searched.
As you can see, this is a somewhat involved process. And yes, this can represent quite a bit of overhead when used extensively. However, in many cases, this approach provides great advantages that are well worth the added overhead.
XAML resources are a great mechanism when used correctly. The trouble starts when they are overused for no apparent reason.
The DynamicResource
object used in this example is just one possible way to deal with resources. Another that's used very frequently is StaticResource
. Both objects can be used to get to resources, but they differ slightly in functionality. The StaticResource
extension uses a one-time lookup, while the DynamicResource
extension creates a link that can be seen as similar to a binding to the resource, which means they will refresh when the resource in question changes, which can be very useful. Note that DynamicResource
extensions are only available in WPF, but not in other XAML versions. In the past, dynamic resources were often believed to pose a performance problem. This fear is overblown. While dynamic resources certainly require some extra work done by the DynamicResourceExtension
object when compared to static resources, the overhead is usually not a big issue. The performance characteristics of dynamic resources should be viewed much in the same light as typical binding operations (which are widely used without fear of performance problems). Most WPF applications with performance problems have issues other than dynamic resources that make them slow.
When Resources Turn into Anti-Patterns
The resource system in all XAML dialects provides very useful features that allow building applications and application characteristics that would otherwise be impossible. For this reason, there are many scenarios where this is quite desirable. However, the trouble starts when this mechanism is overused for no apparent reason. Consider, for instance, the ability to define templates for controls. The following example defines a data template resource that is to be used in a ListBox:
<DataTemplate x:Key="Customer">
<StackPanel>
<TextBlock Text="{Binding Company}"/>
<TextBlock Text="{Binding Contact}"/>
</StackPanel>
</DataTemplate>
This resource can then be applied to a ListBox to make each item in the list appear as defined in the template:
<ListBox ItemTemplate="{DynamicResource Customer}" />
This is great when defining item templates that are reused in a number of different locations. However, when used in just one place, you can define the template within the list box:
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Company}"/>
<TextBlock Text="{Binding Contact}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This performs exactly the same task and achieves exactly the same result, except that the resource system is never used at all, thus side-stepping the overhead that the resource system implies. (And note that in XAML, refactoring the template into a resource later is trivial and can be done in a matter of seconds without any danger of breaking the system. For this reason, you can simply make that change if the need ever arises, and you don't need to plan ahead for it). I would also argue that this makes the code much more readable and maintainable, since everything that goes with the ListBox is now defined within the ListBox. It's easy to see what the ListBox needs. There's also no danger of having unused resources linger around. In most code editors (such as Visual Studio), you could even collapse the ListBox if you didn't want to see anything within its definition, perhaps because you are focusing on other parts of the code.
What makes matters worse is that people tend to use StaticResource
lookups over dynamic ones, which introduces a few additional requirements. For instance, the resource that is statically referenced has to be defined before it can be used (a requirement that doesn't exist for dynamic resources). This means that the resource needs to be defined either further up in the same XAML file, or the resource must have been loaded at a higher scope in the application before the actual UI code loads. In real-world applications, this means that in many XAML files, the ListBox is defined like this (namespace declarations trimmed to keep the example simpler):
<Window xmlns="http://schemas.microsoft.com/..."
xmlns:x="http://schemas.microsoft.com/..."
Title="Customer List" Height="350" Width="525">
<Window.Resources>
<DataTemplate x:Key="CustomerTemplate">
<StackPanel>
<TextBlock Text="{Binding Company}"/>
<TextBlock Text="{Binding Contact}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemTemplate="{StaticResource CustomerTemplate}" />
</Grid>
</Window>
The actual UI definition (the Grid and the ListBox it contains) is at the very bottom of the file, and resources that are used by those UI elements are defined first. It's thus very common that user interfaces have hundreds and often even thousands of lines of resource definitions in a single XAML file (especially resources defined using UI design tools, which tend to be very large - this is true in particular for things like templates or animations and the like), and then somewhere at the bottom, the actual UI definition begins. This creates a very unnatural and conceptually backward flow of definitions within the code file. There is no easy-to-see correlation between the actual UI elements (you can't just collapse the ListBox's code with everything that goes with it, since the resources are broken out separately and independently). It's even hard to see which resources are actually in use and where.
Imagine inheriting a large XAML-based system with this kind of approach! It's exceedingly hard to find your way around in your own XAML code when it's structured like this, but when taking over someone else's system, it's almost impossible. And what is all of this for?!? It doesn't even work as well during runtime as the inline definition! When resources aren't reused, there really isn't any particular reason in breaking objects out into resources. It results in less readable code as well as diminished runtime performance. These are not attributes that are usually considered to be desirable, and there are lots of customers who approach me with projects that are practically impossible to maintain as this mess gets completely out of hand.
How to Solve the Problem
There's a simple solution to all this: Don't use resources when there isn't a reason to do so! If you really need something to be a resource (most likely because you want to reuse it elsewhere), then sure, go ahead. But if your resource is used in only a single element, then move it inline.
Don't use resources when there isn't a good reason to do so!
Whenever you see a resource defined at the top of a XAML file that is then used further down below within that same file, your baloney detector should be going off. If you then discover that the resource is used in only one place, it's time to change something. In most cases, you should simply move the resource inline, as in the example of the ListBox above.
If you feel that the resource is indeed a good candidate to be a resource, move it into a separate resource dictionary file. At CODE, We make it a rule to never define resources within the main XAML UI definition file. For instance, if you create a CustomerEdit.xaml
file, simply add a CustomerEdit.Resources.xaml
file and link to that file like this:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionarySource="CustomerEdit.Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
This way, resources are broken out nicely. The UI definition file now just contains the main UI elements and the resources are nicely filed away elsewhere. You can even swap these resources out whenever you need to keep your app fresh or want to change things for other reasons. You can create multiple resource dictionaries to keep things manageable if you want. Many frameworks (such as CODE Framework: www.codemag.com/framework) automatically load these resource dictionaries for you based on a simple naming convention (and perhaps know which resource dictionaries to load in theme-switching scenarios).
But perhaps in your particular scenario, breaking things out into separate resource dictionaries seems to be a bit much. You may feel it's overkill for what you need. But you know what? If that's the case, that's a clear indicator that the resource really shouldn't be a resource and instead should be defined inline.
Resources are a powerful XAML mechanism that does a very good job for the purpose it was built for. When you have a good reason to use XAML resources, go ahead. You can even feel free to use dynamic resources in WPF, since that mechanism isn't nearly as much of a performance problem as developers often think. But with all that said, avoid resource overuse when there is no real reason to use resources, since it only introduces complexity, maintenance difficulties, code readability problems, and, to top it all off, slower runtime performance. In many applications that I encounter in the real-world, XAML resources seem to be used only because developers aren't even aware that inline syntax is valid in many cases. A problem that seems to have originated with most XAML documentation that always appears is to use resource syntax, which is unfortunate.