Silverlight Xaml Guidelines
One of the key components of any Silverlight (or WPF) application is XAML, as it serves as the definition for every visual element. Being a markup language intended to replace a bunch of UI-creating-code (remember WinForms?), it can quickly get out of control if not properly organized.
After doing some research on the web and asking a few questions, I came up with a few guidelines which I’ll detail in this post.
Static Resources
Static resources are vital in order to avoid unnecessary code XAML duplication. You can define any XAML object as a resource anywhere in the visual tree, and access it by the special notation {StaticResource myKey}.
But as you suppose, not every object may be worthy of being defined as static. There is no point in having a static Button defined in your app, as it will crash whenever you try using the same button in two different places. And if you’ll be using it only once, then why even bother defining it as a resource?
The objects you will be defining most often as resources are Styles, Data Templates, Control Templates, Colors, Brushes and Converters.
Styles
Styles allow you to define sets of default properties for a specific type. For example, you may define a RedButtonStyle, which applies to buttons, and sets some properties such as Background or BorderBrush to reddish colors.
The nice thing about styles is that you may override some of its properties when you apply it. Let’s suppose the following situation:
- A default TextBlock has black foreground, with 11pt Verdana.
- You define a FancyTextBlockStyle, which changes the foreground to Magenta and size to 12pt, and sets the FontStyle to Italic.
- You apply the Fancy style to a TextBlock in your page, but redefine its size to be 10pt.
Due to how Silverlight works, yout final TextBlock will be in Verdana (since you never set a different value, and it is the system’s default), Italic Magenta (as you defined in the style) and size 10pt (as the in-control definition overrides the style).
Styles should be the backbone of your whole XAML architecture, as they allow consistent design throughout the application, and centralize the look-and-feel in a single place, regardless the layout or functionality of the page.
One major drawback for Silverlight is that it still does not implement styles inheritance (as WPF does), so you may find yourself copy pasting a bunch of code.
I am not a fan of implicit styles, so I will not be dealing with them in this post. I’m planning to dedicate a special one for them.
Templates
Templates (both data and control) allow you to define the whole structure of a control. For example, say you don’t like how the default button looks like, and it is not just a matter of background or border. You want a round button. Period.
The only way to achieve this is to create a specific Control Template for it, redefining its whole layout and transitions. It may be a complex task, so I strongly recommend reading further on this subject if you are planning to use control templates. The visual state manager may be the most difficult thing to understand here.
The data template is similar to the control template in the sense that it allows you to specify how a specific part of a control should look like, but they are used generally in the context of items controls. One of the most typical scenarios for a data template is to define the look of an item inside a list box. Therefore, you can assign a collection of model objects to your control, and a data template to render them.
In a data template you will find yourself making heavy use of the Binding notation (which will be further looked upon in this post) to display the fields of the data-bound object. In a control template, on the other hand, the TemplateBinding notation will be your best friend. This saves you from hardcoding certain properties you may want to redefine later, and allows some scenarios like this one:
- You have a ControlTemplate for buttons that redefine their look to be round, and set the background and border using the TemplateBinding notation.
- You have a RedRoundButtonStyle, which applies to a button your RoundButtonTemplate and Red as background and border.
- You have a BlueRoundButtonStyle, which does the same as the one above but using Blue.
This technique may lead to further template reutilization in different styles, which you may also override whenever you use them.
Colors and Brushes
There are several confusions between colors and brushes. Most of the confusions disappear when you realize that colors are structs, and brushes classes. This means that colors are handled by value (and not by ref); they are hardly anything more than an integer (or a 4-byte array to be precise) that identify an ARGB.
Brushes, on the other hand, use colors to paint a region. You may use SolidColorBrushes to paint a whole area with the same color, or GradientBrushes to make some nice gradient effects. But the point is that you are coloring using brushes, not colors directly.
As for the resource notation, you will always want to externalize all colors to your App.xaml file, in order to keep all of them in a single place, and eventually allow support for skinning.
Brushes are a different thing. Having all of your colors represented by a static solid color brush in your App.xaml can save you lots of lines of Xaml. Just think of this:
<Button Background={StaticResource BlueBrush} />
against this:
<Button> <Button.Background> <SolidColorBrush Color={StaticResource BlueColor} /> </Button.Background> </Button>
However, this may lead to some unwanted behaviour. Should you use a color animation to somehow modify the color of your button, what you will be animating is the color used by the brush you used for painting it. And if that brush is a static resource, then you will be changing the background of all of the controls that used that brush. So, handle brushes with extra care.
Resources Location
The resource lookup is made from the control in which the resource is used and up in the XAML tree. If not found, it then retorts to the App.xaml.
This leaves two open options: should you define a resource globally for your whole application to use, or in every UserControl you need them?
Needless to say, resources that are global should be in the App.xaml to be shared by all controls. Other resources, such as Colors and Brushes should also be global, just to keep all color definitions in a single place.
Styles may be defined in a specific user control without worrying, if you are sure you won’t reuse them. This will rarely happen, as if you are not reusing a style, then there is no point to even define it. It might occur when you have a huge user control with a specific style, or when you dynamically generate controls and apply a local style to them upon creation.
Merge Dictionaries
One of the key components for organizing long XAML files are merge dictionaries, which allow you to define a resource dictionary by merging different files. However, Silverlight does not implement them.
So be ready to have a 5k+ lines long App.xaml. Sorting resources by category is a must. And since the lookup is made from the beginning to the end, you will have to define colors first, then the brushes which use them, then the templates and finally the styles which refer to all of them.
Including comments is also necessary for comfortable xaml navigation. A nice trick I found on another page (which I promise to link as I remember which one it was) is to add a sharp before the description of the resource category to be able to find it quickly by Ctrl+F. For example:
<!-- #ButtonStyles –>
User Controls
Make heavy use of user controls. As you don’t have merge dictionaries, unless you implement them yourself (yes, it is possible, although rather painful), user controls are your only way of modularizing your Xaml.
Do not rely on reusability for factoring out a user control from a page. Many times you will find yourself using a user control in a single point of your application. This is no excuse to have a thousand lines long page with all of its sub components declared in it.
Even if there is no need for separate code behind logic, refactoring all visual units into user controls are your best way to keep things tidy.
Do not confuse user controls with custom controls. User controls are designed to modularize visual elements within your project, and you will rarely re use them in a different application, since they are bound to the look and feel of the project they are created in.
Custom controls are the heavily customizable ones. Avoid custom controls unless there is a lack of functionality you need to fill in, such as a WrapPanel or a HeaderedControl. They should never be bound to a style or resource to be found in your App.xaml, if you need to define some look on them, add a dependency property, and avoid hardcoding at all costs.
Naming
Having consistent naming conventions throughout the application is a must. Prefixing control names with Ui in a user control may help you find them quickly, and suffixing them with their type may help avoid confusions. An UiOpenHelpButton is much more declarative than Button6.
However, relying too much on x:Names may be a sign that you are coupling too much your XAML to your code behind, specially if you were planning on using a pattern such as MVVM. Whenever you use a reference to a control by x:Name in your code, think if you could not have accomplished the same by using bindings.
If you are not using commands or attached behaviours and are relying on events, make sure you do not attach to an unnamed control’s event, or at least use a non default name for the handler. Button7_Click is not as declarative as UiOpenHelpButton_Click.
Binding
Binding is an incredibly powerful tool for displaying data and tying your presentation and viewmodel together. Consider it for both ways. If you find yourself setting or reading by code a Text property, then rethink your design.
Many times, however, you will not have the needed property in your data bound object. A frequent case is when you attempt to bind a Visible property (of type Visibility) to a boolean property in the model. In those cases the best course of action is to add a value converter.
Keep a handful of value converters for the most common scenarios, such as displaying datetimes, handling visibilities, number formatting, and so on.
Should there be a more complex situation, it might be better to keep your Xaml cleaner and add a new property in the viewmodel, or a wrapping object if necessary, that exposes whatever complex property is needed.
Containers
Last but not least, the layout of controls in a page is something to take care of. If you design your pages using Blend (or, even worse, have someone else do it for you), you will probably end up with a huge Canvas containing lots of controls with its XY coordinates hardcoded. Or, if you are luckier, a huge grid with its children laid out using margins as if they were global XYs.
Rely heavily on grids or even stack panels instead of a canvas. Don’t be afraid to nest one grid inside the other if that makes sense in your layout (or perhaps you should refactor that inner grid into a user control?).
Do not use rectangles when you can use borders. Avoid absolute positioning as much as possible. Grid positioning, horizontal and vertical alignment are your best weapons here.
This will allow you for easy extensibility of your control, in case you need to add an extra field or resize it to fit somewhere unexpected.
Finally…
Make sure you are consistent throughout the application. Xaml is a rather new language and everyone may feel tempted to inject their own tweaks in it. This leads only to illegibility and, a few weeks later, probably madness.
And do not keep that concept to the Xaml only: your code behind and presentation pattern should be mantained. Pretty much like every other project you develop. Just remember: xaml is a language by itself, and it can be as dangerous as “real code” if not handled properly.
Non First Normal Form
Normalization is one of the key concepts involved when designing a good relational database model. There is quite a lot of theory behind this relatively simple concept as you can see from the wikipedia article.
To make a long story short, you have to evaluate the dependencies between different attributes (for instance, all attributes in a table depend on the primary key, but there can be many more dependencies among the attributes).
These dependencies will result in a grade of normalization of the model, going from first normal form up to the sixth one. The condition for first normal form is just having a primary key, so nearly everything you will do in a relational database will be in first normal form.
There are, however, cases in which first normal form is violated, such as non-relational databases. These are said to be in non-first normal form, and have the particularity of having multi-valued attributes.
| Item | Colours |
| Doll | Pink, Red, White |
| Action Figure | Blue, Black, Brown |
This case would be solved in a relational database by creating an ItemColours table containing item-id and all the colours available (or even better, their keys). But non-relational databases, such as SimpleDb, can solve this in a single table (or domain, as they call it).
What's more, SimpleDb doesn't even require you to define the columns for each domain, as each item inserted can have its own attributes. Therefore, the domain ends up being a collection of items, each item being a set of multi-valued attributes.
| ItemName | Attributes |
| John Doe | Age=20; Phone=555,556,557; Car=Escort,Mondeo |
| Alice Doe | Age=30; Phone=333; Book=DaVinci |
This leads to some very interesting schemas, which may not seem very natural to someone used to a standard database like SQL.
What's most interesting about this is the query language. The fact that attributes are multi-valued leads to some unexpected results, such as 'not a = b' having different semantics than 'a != b'. Let's see why by analyzing the SimpleDb query language.
Without diving into the grammar definition, a SimpleDb query can be represented by something like:
not? ['att1' comp 'val1' op 'att1' comp 'val2' op ...] union|intersection not? ['att2' comp 'val1' op 'att2' comp 'val2' op ...] union|intersection ...
This is, the query is composed by predicates (a predicate is anything between square brackets) joined by set operations: union or intersection, with the possibility to negate them.
All comparisons within a single predicate must be done against a single attribute, and these may be equals, not equals, greater than, etc. The boolean operators to join them are the usual: and|or.
So, if in our example we want all items (well, they are people, but they won't mind if we treat them like items, won't they?) aged above 25, we just query ['Age' > '25']. Range query? ['Age' > '25' and 'Age' < '35']. Multi-predicate query? ['Age' > '25' and 'Age' < '35'] intersection ['Book' starts-with 'Da']. So far so good.
Now to the mean cases. When you have multi predicate queries, the engine evaluates each predicate condition against all of the values of the corresponding attribute, and adds the item if any of the values matches the condition.
Let's suppose we have a numeric attribute (let's forget for now that SimpleDb does not have typed attributes and all are considered strings) called Foo. And we have the following items:
| Item Name | Foo |
| A | 25 |
| B | 25, 35 |
| C | 10, 40 |
| D | 5 |
| E |
The query ['Foo' > '20' and 'Foo' < '30'] will return both items A and B, because the 25 value of B will make the predicate true, and since any of the values verifies, B is added.
Now, if we pick the query ['Foo' > '20'] intersection ['Foo' < '30'], it will return A, B and C. This is because the first predicate will match 40 in C, and the second one will match 10, and therefore C is added. Since the conditions are expressed on different predicates (although they refer to the same attribute) they are not evaluated over the same values.
Therefore ['Foo' > '20' and 'Foo' < '30'] is not the same as ['Foo' > '20'] intersection ['Foo' < '30'].
An excellent example to understand these differences is the one shown in the already mentioned Query 101 article. Consider ['Foo' = '25' and 'Foo' = '35']. This will never return anything, no matter the dataset, since we are requesting all items that have a value for Foo that is simultaneously 20 and 30.
On the other hand, ['Foo' = '25'] intersection ['Foo' = '35'], will return B.
Now to the initial case, the not equals. Let's pick the query ['Foo' != '25']. It will clearly not return A. However, it will return B, because when the predicate is evaluated on the 35 value, it is true, so B is added to the result.
The query not ['Foo' = '25'] will have the expected behaviour, and return items C and D. It will also return E, because E has no value defined for Foo, so any comparison over Foo will be false, and its negation, true.
Manipulating data is also non-trivial. Whenever you update an item, you must specify whether the new values should be added to the existing ones or replace them.
To sum up, working with denormalized may be appealing during the modeling process due to its flexibility; but it requires being extra careful when querying and manipulating the data.
Nevertheless, bear in mind that the lack of normalization enforcement frees up a lot of database resources that (supposedly) allow for a much greater scalability and handling huge amounts of data. And this is what you should have in mind when you consider whether to use a relational or a completely denormalized database, since this will have the greatest impact on your users.
Remember that unnatural queries can be dealt with much easier than a whole crippling database already deployed onto production.
Command pattern in Web Apps
The command pattern is a behavioural pattern that encapsulates a request made to a certain object inside a Command object. Each type of command knows how to Execute() itself, as well as its target instances.
In the example above, taken from the Gang of Four's Design Patterns, a PasteCommand would be associated to the Paste menu item. When the item is clicked, the command is executed, and, having a reference to the Document, calls Paste() on it.
This pattern is useful when you want to defer the execution of a certain command, for example, or store a log for a given transaction to be able to recover from a crash. It also allows you to define a high-level language for operations within your system.
However, the motivation for it in this case is to be able to support undo/redo operations. This requires a number of additions to the standard Command pattern.
First of all, the abstract Command class must implement Undo() and Redo() methods, aside from Execute(). It will also probably need an old state object, in order to know how to go back to the previous state before its execution. Therefore, having OldState and NewState fields in each command is a good practice to give the command all the information it needs for execution. The Sender of the command mayalso be required.
To handle these commands, a global History object is necessary. This object has a collection of listeners that implement a certain interface (in the example, the Document), and methods to Execute a command, Undo and Redo.
The mechanics would be the following: at the beginning of the application all listeners subscribe to the History class. When an option is selected, a Command is created with current and next state, and sent to the history for execution (note that current state can be obtained from a State provider).
History then executes the command for each of its listeners, which will decide whether to take action based on the command type and parameters. And then it stores the command inside a list for undoing and redoing.
When the history receives an Undo message, it looks for the last executed command and calls its Undo() method. In order to support multiple undo operations, the history must keep a current command index.
Grouping commands requires special attention. Sometimes a single action may trigger more than one command (for example, clicking on a link may involve OpenBrowserCommand and NavigateToCommand). However, if the user undoes and redoes this action, the browser will first open in an empty browser and only navigate in the next redo, exposing the nature of the commands to the user.
In order to avoid this, one possibility is to have a MacroCommand object that contains multiple commands. Whenever it is executed, it invokes the Execute() method of all of its children, same as Undo() and Redo().
The problem with this is that a single action may involve several components. For example, when a browser is created, it may decide on its own to launch a NavigateToCommand. We can't group this with the previous command as it depends on its execution.
This is when timing commands comes in handy. By adding a timestamp to each command, the undo and redo operation can be done by timespans. Therefore, when the History receives an Undo message, we don't undo the last command, but the commands executed in the last second.
Dealing with time is always problematic. A command that takes too long to execute may exceed this threshold, and a fast-clicking user may trigger two different actions within the timespan, and be undone together. Tuning this threshold is more difficult and error prone than the MacroCommand alternative, yet much more flexible.
The usage of commands in a web application is also good for logging. Whenever a command is issued, logging its parameters and states allow you to keep a trace on the user actions. With appropriate analysis tools, it can allow you to extract metrics on actual user reactions upon the interface. Knowing that all users entering the "Configuration" page are leaving without altering its content could mean that the page is not very intuitive (if not scary).
It also allows you to inject different aspects into the system, such as providing help based on the user actions, which will hopefully be the subject of the next post.
Update: As Martin pointed out, GWT provides a History object that allows you to manage the browser's back and forward buttons, by storing states (commands) within the browser's history stack and responding to changes via listeners.