4

有人知道何时分配控件的 UniqueId 吗?

现在我的 Page_Init 中有一些基于 UniqueId 的代码。但是,根据某些业务逻辑,我可能需要在此发生之前重新排列页面的控制层次结构。

所以,我的主要问题是,UniqueId 是什么时候分配的?我是否可以重新排列 Page_PreInit() 中的层次结构,以便当我的代码在 Page_Init() 中触发时,我将分配正确的 UniqueId?

4

3 回答 3

6

为了回答这个问题,我编写了一个小的隐藏代码,用于记录每个事件的控件的 UniqueID 属性的值:

  • 预初始化
  • 在里面
  • 初始化完成
  • 预载
  • 加载
  • 加载完成
  • 预渲染
  • 预渲染完成

例如,最后一个事件处理程序如下所示:

protected void Page_PreRenderComplete(object sender, EventArgs e)
{
    _uniqueIdValues.Add(
        new Tuple<string, string>("PreRenderComplete", MyControl.UniqueID));
}

然后,我在 Unload 事件中设置了一个断点,并使用 Visual Studio 的即时窗口打印出记录的值:

_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)}

对于每个事件,UniqueID 似乎都设置为字符串“MyControl”(实际上是我在 ASPX 标记中为控件指定的 ID 属性)。MSDN 中@Rewinder 的回答似乎是正确的。这些是在触发任何 ASP.NET 页面级事件之前设置的。

编辑:

如果我们查看 System.Web.UI.Control 的 .NET 3.5 参考源 (http://referencesource.microsoft.com/),我们可以看到 UniqueID 的返回值是在访问属性时计算的。UniqueID 属性如下所示:

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;
        }
    } 
}

并且,当命名容器更改时,将调用以下方法。ClearCachedUniqueIDRecursive 方法重置 _cachedUniqueID 字段的值,以便在下一次调用 UniqueID 属性时重新生成它。

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; 
}
于 2011-03-29T13:24:00.800 回答
1

我是否可以重新排列 Page_PreInit() 中的层次结构,以便当我的代码在 Page_Init() 中触发时,我将分配正确的 UniqueId?

我无法准确说出您要做什么,但听起来微软不鼓励这样做:

通常,您不需要使用 UniqueID 属性。例如,您不应该使用生成的 UniqueID 属性的预测值来编写引用控件的代码。您可以读取 UniqueID 属性的值并将其传递给其他进程,但不应依赖它具有特定结构。

于 2011-03-29T13:15:08.960 回答
0

来自MSDN

此标识符是在处理页面请求时自动生成的。

所以是的,您可以在 PreInit 期间访问 uniqueId

编辑

好吧,我想我有点模糊。Page.ProcessRequest调用该FrameworkInitialize()方法,该方法将构建控制树。这发生在 PreInit 之前,因此控件的 UniqueId 可用。

于 2011-03-29T13:01:21.560 回答