Control.UniqueId 何时创建?

发布于 2024-10-27 20:49:50 字数 224 浏览 11 评论 0原文

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

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

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

Does anybody know when a control's UniqueId is assigned?

Right now I've got some code in my Page_Init that is based off the UniqueId. However, depending on some business logic, I might need to rearrange the control hierarchy of the page before this happens.

So, my main question is, When is the UniqueId assigned? Is it possible for me to rearrange the hierarchy in Page_PreInit() so that when my code fires in Page_Init(), I'll have the proper UniqueId's assigned?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夜唯美灬不弃 2024-11-03 20:49:50

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

  • PreInit
  • Init
  • InitComplete
  • PreLoad
  • Load
  • LoadComplete
  • PreRender
  • PreRenderComplete

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

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”(实际上是我为控件指定的 ID 属性)每个事件的 ASPX 标记中)。 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; 
}

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; 
}
ぽ尐不点ル 2024-11-03 20:49:50

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

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

通常,您不需要使用
UniqueID 属性。例如,
你不应该编写这样的代码
通过使用引用控件
生成的预测值
唯一 ID 属性。您可以阅读并
传递UniqueID的值
其他进程的财产,但你
不应该依赖它有一个
具体结构。

Is it possible for me to rearrange the hierarchy in Page_PreInit() so that when my code fires in Page_Init(), I'll have the proper UniqueId's assigned?

I can't tell exactly what you are trying to do, but it sounds like Microsoft discourages it:

Typically, you will not need to use
the UniqueID property. For example,
you should not write code that
references controls by using a
predicted value of the generated
UniqueID property. You can read and
pass the value of the UniqueID
property to other processes, but you
should not rely on it having a
specific structure.

软糯酥胸 2024-11-03 20:49:50

来自 MSDN

该标识符已生成
当页面请求时自动
已处理。

期间访问 uniqueId

所以是的,您可以在 PreInit编辑

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

From MSDN:

This identifier is generated
automatically when a page request is
processed.

So Yes, you have access to the uniqueId during PreInit

EDIT

Ok, I guess I was a bit vague. Page.ProcessRequest calls the FrameworkInitialize() method, which will build the Control tree. This happens before PreInit, therefore the control's UniqueId is available.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文