Introduction
This is another small article on my series about ASP.NET controls, and its main focus is to reveal how controls are related to each other, which entities are involved, and what are their main roles in this task.
Motivation
Understanding the small pieces of magic that happen underneath our noose every time a Page request is handled and someone gets your web form in his browser will help you avoid many problems, to debug them faster, and to produce better applications.
If you're an experienced programmer, this knowledge may also help you to orchestrate complex workarounds and perhaps step through some of the ASP.NET constraints.
How controls are related to each other?
In order to expose an ASP.NET form, you need to place it in a Page
, in fact, in any ASP.NET Control. In order to participate in the Page lifecycle, you need to be somehow related to the Page. This relation is achieved by a parent/children hierarchical structure.
The Page
control is the root control of this hierarchical relationship, and is the one that handles which pipeline should be triggered (initial request, a postback request, or a callback request).
A control can, if needed, contain other controls, and all those child controls are kept together in a ControlCollection
instance that is exposed through the Controls
property. Every control knows its Parent
Control.
A control that can contain other controls can also be marked as a participant in the automatic naming generation process of its descendents. This role is achieved by implementing the INamingContainer
interface, and when this happens, the control is said to be a NamingContainer
. Every child control will know its NamingContainer
.
The ControlCollection
provides the usual set of methods for collection management:
Add
- Adds the specified Control
object to the collection.Remove
- Removes the specified server control from the parent server control's ControlCollection
object.Clear
- Removes all controls from the current server control's ControlCollection
object.
A control can only be attached to another and become its child through the ControlCollection.Add
method. Every time a control is added or removed from a collection, both its parent and its NamingContainer
are notified and will react.
When a control is added to another control's children collection, the new parent Control.AddedControl
method is invoked and the following steps are taken:
- Check if the newly added child control has an owner and therefore if its use is restricted only to that owner control. If true, the child is not a valid control and an exception is thrown.
- Check if the newly added child control belongs to another control's children collection, and in that case, the control will be removed from its previous parent's children collection. This is required to ensure a valid hierarchical relationship: a control can only belong to a single
ControlCollection
. - Update the Page reference of the newly added child control to reference the new parent Page.
- Update the parent reference of the newly added child control to reference itself. If the new parent control is a
NamingContainer
, then we will update the NamingContainer
reference of the newly added child control to reference itself. - If the new child control ID has not been specified, then a new ID is automatically generated for the
NamedControls
collection of the new child control, and the NamingContainer
is marked as dirty to ensure that a new and fresh collection is created and populated. - If possible, the control life cycle is recreated for the newly added child control.
When a control is removed from its parent ControlCollection
, the parent Control.RemovedControl
method is invoked and the following steps are taken:
- Check if the newly added child control has an owner and therefore if its use is restricted only to that owner control. If true, the child is not a valid control and an exception is thrown.
- The
NamedControls
collection of the child control NamingContainer
is marked as dirty to ensure that a new and fresh collection is created and populated (without the removed control). - The child control performs an
UnloadRecursive
without disposing. - All references set at
AddedControl
are removed and the control is released from any hierarchy.