Silverlight Loaded Events

A common scenario in the development of GUI applications is the presence of different events fired by the engine as the visual tree is constructed and rendered. And Silverlight, of course, is no exception.

While WPF provides Initialized and Loaded events for all framework elements, Silverlight has only the latter. There is also a LayoutUpdated method, but (as we will see in a few moments) is not very useful.

To check the order of the events fired by Silverlight when rendering the visual tree, I created a small test: it consisted in a grid containing a border containing a textbox. I wrote handlers for the Loaded, SizeChanged and Layout events, and outputted them to the console.

Note that MSDN recommends NOT to use javascript's alert method to check the order of the events fired, since it could not match the real one. Don't ask how this might happen.

Also, if you are dealing with a User Control you built yourself, there is also the possibility to override the Measure and Arrange methods, which correspond to the two passes the Silverlight engine makes when deciding the layout of the visual tree. Here I will limit the test to events visible from the outside.

Here is the output of the first test run. I'm writing the control's name (level means the level within the tree), its render size, and margin set. The last one will serve as a witness to know when it is actually set, being specified in XAML.

As expected, the Loaded event gets fired first, since (according to the documentation) it is fired when all properties are set (note that margin's value is 1). Also notice that it is fired in the leaves first, since there is no point in setting the "Children" property of a control and raising its loaded event, having unloaded children.

Then, SizeChanged is fired, which makes sense if you consider that size has gone to a valid value from no size at all. The problem here is that the root fires first. You will soon see why this is a problem.

Finally, Layout methods are fired, without any information of the sender at all (just a null reference), which renders it completely unusable.

Another test I decided to undertake was adding more controls to the grid, and check in which order they were loaded/drawn: position in grid or order of creation in XAML.

Loaded events are fired in order of creation in XAML, which makes sense. The big surprise is that size changed events are fired in exactly the opposite order. And Layout keeps the same behaviour as usual: none.

Now, to the motivation of this post. I had a relatively complex user control, which contained several children, and I needed to position a selection window over it, based on the position of the children.

The problem is that there was no event I could attach to in the user control that could notify that all children were fully rendered, since the control's SizeChanged fired before its children's. And I definitively wanted to avoid LayoutUpdated.

So I wrote a small class, the RenderNotifier, that attaches itself to a control and receives a list of children to monitor. When all of them raise their size changed events, the RenderNotifier raises its own RenderComplete event.

It contains a list of children and attaches itself to each SizerChanged event, and detaches on remove.