Wednesday, January 12, 2011

An Animated Custom Panel base class for WPF and Silverlight

If you have used XAML at all, you will have used some of the built in layout panels such as Grid and StackPanel and if you are a developer you have probably developed a custom panel that implements your own layout logic. In case you haven’t, here’s a brief explanation. WPF and Silverlight use a two-pass scheme, where first all elements are measured by calling the panel’s MeasureOverride method. In this method you are supposed to call Measure on all your children and ask them how much space they would like. In the second pass, your ArrangeOverride method is called and the panel then actually performs the layout of its children, usually taking note of the child’s DesiredSize property and then calling Arrange passing the size and position of the children. There is really not much more to a custom panel than the ArrangeOverride and MeasureOverride methods but obviously the custom layout logic can be as complicated as you like.

Way back in 2006, Martin Grayson and I published an article showing an animated custom Fish-Eye panel that implemented a layout not dissimilar to Apple’s hyperbar on OSX that grows as you mouse over each element. Obviously we’ve done lots of custom panels since then, but one recurring theme is that really a panel should not modify its children. In the Fish-Eye example, the panel arranged all the children at (0,0) and applied animated transforms to move the children into place. If the child wanted to set its RenderTransform itself, it couldn’t, as the panel would overwrite it. Also creating lots of animations in code seemed a bit wasteful.

Another technique was used by a colleague, Stuart Richardson, which is not to use Animations at all, but hook CompositeTarget.Render and call InvalidateArrange on each frame redraw, then recalculate the positions of all the children and arrange them in the right place. This way you are not modifying the children at all, just positioning them. After we had successfully used this technique for many panels, Martin suggested a base class that would handle all the CompositeTarget.Render logic that panels requiring animation could inherit from. So I took the idea and wrote the AnimatedPanel class that this article is about.

Read more: MCS UK Solution Development Team