Why I Don't Like Canvas

In Silverlight 1.0, the only container element was Canvas. In Silverlight 2, there are a number of other layout containers, such as Grid, Border and StackPanel, and you can also make your own. Silverlight 2 applications can be completely layout-based and not rely on absolute positioning at all. Of course, you can still use Canvas. But should you? Most of the time, the answer is "no".

The usage of Canvas elements in controls and layout containers is often an anti-pattern and should be avoided. Unless you have some sort of user physics/drawing/design/charting surface or something else where thinking in any terms other than absolute positioning in a coordinate system is unnatural, you should not be using a Canvas anywhere.

Here are some of the reasons why:

Canvas always returns 0,0 for its desired size in MeasureOverride.
For layout purposes, no space will ever be allocated for a Canvas, even if the Canvas has a Width and Height set. For example, if you put a Canvas inside of a StackPanel, the StackPanel will not allocate any space for the Canvas no matter what.

Canvas returns exactly what it was given in ArrangeOverride.
This means that layout will never impose a clip on the Canvas, even if the Canvas has a Width and Height set and those exceed the space that layout is giving it. The example here is that you have a Grid, and you put a Canvas inside of it. The layout system will not clip the Canvas since it will never exceed the size it was given.

Canvas measures its children at infinity,infinity.
Children can be as big as they want to be. This may not be bad in and of itself, but if you want the children to fit into a container, you can just let layout do it for you. It is likely that you'll have to specify the sizes of a Canvas's children explicitly.

Canvas arranges its children at their desired size, and places them at their Canvas.Top/Left.
The Children of a Canvas can effectively be anywhere on the screen, and will not cause clipping (although they will be clipped by other explicit or layout clips in the ancestor chain). If this is a behavior that you need, you can use a TranslateTransform or negative Margins instead.

It may sound like I’m pretty down on Canvas. Well, yeah. They can be easily misused, and can cause more trouble than they are worth. The layout system can handle lots of things for you, and you should let it. Spend your time doing what only you can do, rather than duplicating layout functionality.

For example, let's say you are making your own little ScrollBar. We already have one you can use, but never mind, you want to make your own. You could inherit from UserControl (if you don't care about templating), and inside of the UserControl, put a Canvas with two RepeatButtons, a Rectangle (for the track) and a Thumb, and then when the Control is measured, calculate how much space you need for all of those things, and when your ScrollBar is arranged, figure out how where everything should go, and set the Canvas.Top, Canvas.Left, Width and Height properties on each of your elements. And that's what you would have had to do in Silverlight 1.0. But now, using Silverlight 2, why not let the layout system do the work for you?

Try using a Grid with three cells. Put the RepeatButtons in the first and third cells. Put a Rectangle in the second cell, then the Thumb (Grid can contain multiple children. If they are in the same cell, they will just be placed on top of each other, and can be manipluated with the Margin, HorizontalAlignment and VerticalAlignment properties.) Use the Margin property to move the Thumb around within its cell, based on the Value property.

I mentioned some of the typical reasons to use Canvas above. But are there creative uses of Canvas that take advantage of the very things that I whinge about? Of course. I can think of a few. Can you?