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.

Leave a Reply

Your email address will not be published. Required fields are marked *


6 × = thirty

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>