My question is simple: WHEN (on what event?) can I be sure that a control has fully loaded and has its states and templates also?
Why am I asking:
I'm trying to restore the state of my own WP7 control after recovering from tombstone. This control looks like a calendar in a weekly view. In this calendar you can select many items displayed as colored Rectangles.
If I select any of them, and then go to tombstone and come back to the page, it seems like my control forgot which Rectangles
were selected. In fact, it did NOT forget the data itself, but the Rectangles
forgot their selected state.
After recovering from tombstone, I try to select the Rectangles
by setting their VisualState
to "Selected" (which works in any other scenario). I found out, that it fails, because VisualStateManager
can't find the "Selected"
state.
I know this is tricky, because when coming back from tombstone the controls do not build exactly as in any "normal" case. (for example Bindings
and Templates
do not apply in the same order) But up until now I could always trust, that when FrameworkElement.Loaded
fired, I had my controls ready. Now it seems like VisualState
is not. (I tried to set the state from Loaded
event handler, but results are the same, VisualStateManager.GoToState
returns with false
.)
What more can I do?
This is a tricky one! I have also experienced issues where UI events fire before the UI itself is fully constructed, see this blog post for an example. My general approach to this is to handle the LayoutUpdated
event, which fires each time the visual tree is updated. You will find that this event fires multiple times, both before and after the Loaded
event.
When the Layoutupdated
event fires, you can check whether the visual state change has worked, if so, no longer handle the event. If not, keep trying!
Within your loaded event, try the following:
// try to set the state
if (VisualStateManager.GoToState(myControl, "myState") == false)
{
// if failed, wait for the next LayoutUpdated event
EventHandler updateHandler = null;
updateHandler = (s, e2) =>
{
if (VisualStateManager.GoToState(myControl, "myState") == false)
{
myControl.LayoutUpdated -= updateHandler;
}
};
myControl.LayoutUpdated += updateHandler;
}