To answer this question, I wrote a small code-behind that logs the values for the UniqueID property for a control for each of these events:
- PreInit
- Init
- InitComplete
- PreLoad
- Load
- LoadComplete
- PreRender
- PreRenderComplete
The last event handler, for example, looked like this:
protected void Page_PreRenderComplete(object sender, EventArgs e)
{
_uniqueIdValues.Add(
new Tuple<string, string>("PreRenderComplete", MyControl.UniqueID));
}
Then, I set a breakpoint in the Unload event and used Visual Studio's Immediate Window to print out the logged values:
_uniqueIdValues.ToArray()
{System.Tuple<string,string>[8]}
[0]: {(PreInit, MyControl)}
[1]: {(Init, MyControl)}
[2]: {(InitComplete, MyControl)}
[3]: {(PreLoad, MyControl)}
[4]: {(Load, MyControl)}
[5]: {(LoadComplete, MyControl)}
[6]: {(PreRender, MyControl)}
[7]: {(PreRenderComplete, MyControl)}
It appears that the UniqueID was set to the string "MyControl" (which was in fact the ID property that I had specified for the control in the ASPX mark-up) for each of the events. It would seem that @Rewinder's answer from MSDN is correct. These are set before any of the ASP.NET page-level events are triggered.
EDIT:
If we look at the .NET 3.5 reference source (http://referencesource.microsoft.com/) for System.Web.UI.Control, we can see that the return value of UniqueID is computed when the property is accessed. The UniqueID property looks like this:
public virtual string UniqueID {
get {
if (_cachedUniqueID != null) {
return _cachedUniqueID;
}
Control namingContainer = NamingContainer;
if (namingContainer != null) {
// if the ID is null at this point, we need to have one created and the control added to the
// naming container.
if (_id == null) {
GenerateAutomaticID();
}
if (Page == namingContainer) {
_cachedUniqueID = _id;
}
else {
string uniqueIDPrefix = namingContainer.GetUniqueIDPrefix();
if (uniqueIDPrefix.Length == 0) {
// In this case, it is probably a naming container that is not sited, so we don't want to cache it
return _id;
}
else {
_cachedUniqueID = uniqueIDPrefix + _id;
}
}
return _cachedUniqueID;
}
else {
// no naming container
return _id;
}
}
}
And, the below method is called when the naming container changes. The ClearCachedUniqueIDRecursive method resets the value of the _cachedUniqueID field so that it is regenerated on the next call to the UniqueID property.
private void UpdateNamingContainer(Control namingContainer) {
// Remove the cached uniqueID if the control already had a namingcontainer
// and the namingcontainer is changed.
if (_namingContainer != null && _namingContainer != namingContainer) {
ClearCachedUniqueIDRecursive();
}
_namingContainer = namingContainer;
}