ContentPresenter.Loaded not raised when the control is initially created as collapsed
Perhaps hoping in a miracle, but let's try :-)
MyControl derives from Control. Its ControlTemplate contains
<ContentPresenter ContentTemplate="{TemplateBinding EditorTemplate}"/>
(Other details are omitted.)
Derived controls supply suitable EditorTemplate. For example MyTextControl specifies template consisting of a TextBox. (With proper bindings, of course.)
I won't describe what works (most scenarios), but what does not:
A collapsed MyTextControl instance is created. Later on this control is made visible. Here is what happens:
- MyTextControl instance created, set to Collapsed
- MyTextControl.Loaded event: At 开发者_如何学JAVAthis moment the visual tree contains MyTextControl with no children.
- In the Loaded handler I call ApplyTemplate(). In turn the visual tree is modified to MyTextControl -> ContentPresenter. That's all, no more children.
- Stil in Loaded handler, I assign Loaded handler to the ContentPresenter.
- Sometimes later the control is made visible. Its visual tree gets populated by TextBox internals: Border -> ContentControl -> ContentPresenter -> internal TextBoxView. In other words the control just works.
The problem is that the ContentPresenter Loaded handler was not called, i.e. I am not able to identify the moment when the control is ready.
I tried an alternative solution, i.e. instead of forcing ApplyTemplate() I simply waited in MyControl.OnApplyTemplate(). The sequence:
- MyTextControl instance created, set to Collapsed
- In the Loaded handler the visual tree contains MyTextControl with no children.
- The control is made visible.
- In OnApplyTemplate() the visual tree is MyTextControl->ContentPresenter.
- Stil in OnApplyTemplate(), I assign Loaded handler to the ContentPresenter.
- The rest is as before. The visual tree is populated by TextBox internals (the control works), but the above handler gets not called.
Does anybody know a way how to identify the moment when the control is fully loaded?
Note that I did the above with several other MyControl-derived controls. For each of them one of the above scenarios worked (sometimes one, sometimes another), but the TextBox-based control is the first one where I am not able to identify moment of loading.
Also note that this problem does not happen when the control is visible for all the time.
Ok, I'll answer myself. My current conclusion after 1 day and dozens of tests is that Loaded event is for birds. It happens on various stages of the control life cycle and in case of composite controls there is no warranty that the control is fully functional. In some cases it might be not fired at all.
Forcing template building by calling ApplyTemplate() is no solution either as in some cases it may result in building partial control tree.
OnApplyTemplate suffers similar problems - it might be called when only partial control tree is built.
After acknowledging the above statements I decided to give a try to LayoutUpdated event. I set up the handler in OnApplyTemplate() (I tried to use latest possible moment) and investigated the control tree. As a first approximation it seems to be sufficient to check if the ContentPresenter has children. If so, we'll say that the control is loaded and unregister LayoutUpdated handler. A more sofisticated test could be used, but the trivial one I just described is working for wide range of controls.
Originally I was afraid that the LayoutUpdated solution will be inefficient, but it looks like (using the described organization) the first handler call is exactly the place when the control is "loaded".
精彩评论