Skip to main content
Home Forums Silverlight Programming Silverlight Controls and Silverlight Toolkit When is an object hierarchy completely loaded? Loaded event is unreliable.
8 replies. Latest Post by RobertMcCarter on November 27, 2009.
(0)
andulvar
Member
155 points
102 Posts
10-21-2008 8:42 AM |
I have an application that is causing me grief with the Loaded event. I derive a class from Grid (call it Outer), and a class from DependencyObject (call it Inner). Inner is a child of Outer. When both are loaded I want to assign Inner as the DataContext of Outer. Logically, I should do this work in the Loaded event of Outer. Alternatively, I could do this work in the OnApplyTemplate method of Outer. It doesn't work reliably because I cannot predict whether Inner exists when Outer's Loaded event fires.
If Inner is fully defined within the XAML of Outer, it appears to work. If Inner is templated, so that its own properties are assigned through {StaticResource...} then Inner is not yet defined when Outer's Loaded event fires. Consequently when I assign Outer.DataContext = Inner, this throws an error (argument is out of expected range) presumably because Inner has not yet been initialized in some fashion. This post: http://silverlight.net/forums/p/11996/39114.aspx#39114 implies that the order is fixed. It clearly is not.
I'm doing all this because if I try to assign Outer as its own DataContext (basically: this.DataContext = this), it always fails with the same error message. It looks like the object state has to pass a certain point in the construction process before it can be assigned as a DataContext.
I tried to make Inner a FrameworkElement or a Control so I could count Loaded events, and do the work only when two Loaded events have occurred. This can only work because Inner and Outer are both my code, and they know about each other. The problem is that Inner's Loaded event can fire zero, one or multiple times. I haven't figured out what causes that, other than to note that if there is a try/catch in some processing that precedes Inner's Loaded event, and an error is caught, this could stop Inner's Loaded event from happening at all. In the debugger I once saw Inner's Loaded event get called 6 times in a single run. I can't tell you why.
I considered calling ApplyTemplate manually in the Loaded event of Outer. Unfortunately, Grid does not have an ApplyTemplate method. Why not? It has an OnApplyTemplate override. Strangely, the OnApplyTemplate method of Outer never actually gets called. If I make Inner into a FrameworkElement, its OnApplyTemplate never gets called either.
I've read this post: http://silverlight.net/forums/p/27294/93181.aspx#93181 which deals with the question of Loaded order somewhat, but doesn't address the issue for objects without an ApplyTemplate method. It also doesn't address the issue of Loaded firing a random number of times.
So, after all this, I have one simple question:
At what point in the code can I be guaranteed that my object (in general, a DependencyObject) and all of its children are completely loaded?
10-22-2008 6:40 AM |
I've been wrestling with this some more. Since "Loaded" does not tell us anything about the state of either the parent or the children of a control, it is the wrong event in which to handle logic that relies on the hierarchy. We need two new events, both of which fire immediately before the root object is returned from XamlReader.Load() or whatever function internally loads object hierarchies.
The first event should propagate from the root of the hierarchy to the leaves, called something like "ParentReady". Its purpose is to say "The entire tree is now loaded, initialized and rendered, and your parent has processed its ParentReady event." This is the event that tells the object that its parent has done whatever initialization that its children must rely on.
The second event should propagate from the leaves of the hierarchy to the root, only after the entire hierarchy has processed "ParentReady". This second event could be called "Ready" and would be the last event transmitted before the loading process is done. The purpose of the "Ready" event is to tell an object that its children have completed any initialization that the parent must rely on.
The important criteria before these two events fire would be:
This would resolve many outstanding issues that I see in the forums, like:
10-29-2008 11:03 AM |
Who keeps marking this as answered? Nobody has even replied to it.
Iceczd
16 points
12 Posts
10-30-2008 9:15 AM |
In Silverlight 2 Beta 2. The Loaded event would occur once the control was rendered, now in the Release it seems to Happen before.
This broke my workaround for an issue with the scrollviewer class being rendered with too many child objects at once (causing many height calculations and whatnot)
Silverlight Devs, take these issues Seriously!
And please realize everytime you make a change your affecting thousands of peoples code.
The font change from b2 to rc1 was enough. We've had to reformat loads of content to compensate.
CleverCoder
203 points
157 Posts
11-26-2008 5:18 PM |
This has also affected me. According to the docs:
"Occurs when a FrameworkElement has completed layout passes, has rendered, and is ready for interaction."
Nay! I have a Popup control that contains an ItemList. I have attached a handler to the ItemList.Loaded event.. and it seems that every so often (perhaps 1/10 of the time), I can't get the ActualWidth of the ItemList in that Loaded event. This causes bad behavior when the position of the list needs to be positions when it is loaded. Bad things happen 8*(
Anyone else seen this? I think hooking up the LayoutUpdated and checking ActualWidth for non-zero might be the only solution for now.
Boooo!
centrox
2 points
1 Posts
10-19-2009 2:19 PM |
I'm having the same issue here with SL3.
Having nested templated objects, and setting breakpoints at all events, will ofcourse show us the order of things..Although I have not experienced random behaviour. It is always the same.
In my situation the loaded event is the first of the following sequence of events:
Loaded, OnApplyTemplate,ArrangeOverride,LayoutUpdatedContext of this list is a class inherrited from Control. And it is always in the same order.The first workaround that i feel myself pushed into by this framework is to put my 'One time only' logic in the layoutupdated class with a nasty alreadyfired flag. But i can't beleve this is the only way to get things done after they have properly initialized and ready to use.Anyone else some thoughts?
Cheers Centrox
snortblt
12 points
13 Posts
10-19-2009 3:46 PM |
Agreed. This is very frustrating. Certainly this must be a very common use case. If loaded doesn't really mean everything's loaded, its nearly useless.
RobertMc...
35 points
23 Posts
11-27-2009 10:13 AM |
I'm voting for this as well - "this.DataContext = this" is often very useful, and getting a "AG_E_PARSER_BAD_PROPERTY_VALUE" is definitely NOT helpful, and in no way actually describes the problem.
11-27-2009 10:36 AM |
While modifying a few other controls on my page, I started getting "AG_E_PARSER_BAD_PROPERTY_VALUE" errors on controls that I haven't touched in weeks, and on properties that are completely valid and normal (and have been working for weeks).
This is very very odd, please address this problem.