1

我有一个动态添加到自定义 GridView 的 TemplateField。

void ITemplate.InstantiateIn(System.Web.UI.Control container)
    {
        switch (_templateType)
        {
            case ListItemType.Header:
                if (this.ParentGridView.ShowDeleteHeaderImage)
                {
                    Image hImg = new Image();
                    hImg.ImageUrl = this.ParentGridView.DeleteHeaderImageUrl;
                    hImg.AlternateText = "Mark for Deletion";
                    container.Controls.Add(hImg);
                }
                else
                {
                    Label l = new Label();
                    l.Text = "Del";
                    container.Controls.Add(l);
                }
                break;
            case ListItemType.Item:
                container.Controls.Add(new CheckBox());
                break;
            case ListItemType.EditItem:
                break;
            case ListItemType.Footer:
                QLImageButton deleteButton = new QLImageButton();
                deleteButton.Settings.ImageId = "cmdQLGVDelete";
                deleteButton.Settings.ImageUrl = this.ParentGridView.DeleteImageUrl;
                deleteButton.CommandName = "Delete";
                container.Controls.Add(deleteButton);
                break;
        }
    }

为了响应网格命令(插入/更新/删除),调用了一个名为 GetRowControls 的方法,该方法遍历特定网格行中的列,并将其每个控件添加到字典中。

Dictionary<string, WebControl> GetRowControls(GridViewRow row)
...

rowControls.Add(ctrl.ID, (WebControl)ctrl);

...

因此,这对于以声明方式添加的模板字段和绑定控件以及以编程方式添加的动态非模板字段都适用。

但是,当控件是动态添加的 TemplateField 控件时,ctrl.ID 始终为 null,因此上面的语句会引发异常。

我用 Reflector 研究过这个问题,因为我发现当我在 VS 2005 的即时窗口中检查变量时,即 ?ctrl,ctrl.ID 会列出一个值。我已经确定这是因为在即时窗口中列出 ?ctrl 时,调用了属性 ClientID 并且 ClientID 调用了 EnsureId(),而后者又设置了 ID。

public virtual string ClientID
{
    get
    {
        this.EnsureID();
        string uniqueID = this.UniqueID;
        if ((uniqueID != null) && (uniqueID.IndexOf(this.IdSeparator) >= 0))
        {
            return uniqueID.Replace(this.IdSeparator, '_');
        }
        return uniqueID;
    }
}

所以我假设 ClientID、UniqueId 和 ID 都是空的——尽管如上所述,只读取前两个将触发所有设置。另请注意 NamingContainer 不为空。它已被设置。

所以解决这个问题非常简单,即检查 ctrl.ID==null,如果是这样,只需读取 ctrl.ClientID。这就是我所做的,因为从时间上讲,我真的需要继续努力。但是,如果有人不自觉地知道答案,我仍然对答案感兴趣。

为什么动态添加的 TemplateField 的子控件的 ID 值设置在与其他控件不同的时间?

4

2 回答 2

2

并不是它们的行为不同,而是几乎总是当您以声明方式添加控件时,您会立即设置 ID。尝试将没有 ID 的标签添加到页面并浏览控件集合并检查其 ID,它将为空(确保不显示其 clientID,因为它会填充 ID):

<asp:Label runat="server">something</asp:Label>

另请注意,如果您像这样运行它,您将获得一个没有 ID 的跨度。

于 2009-04-01T17:42:34.617 回答
2

弗雷迪是正确的。

您负责在 InstantiateIn 方法中设置 ID。如果没有另外指定,ClientID 会自动生成它们是有道理的。

声明性控件在页面编译期间获得由页面构建器分配的 ID。如果您要查看在“临时 ASP.NET 文件文件夹”中生成的临时 .cs 文件之一,您会发现类似这样的内容(去除了编译指示):

//creating a template field, where CopiledBindableTemplateBuilder is the ITemplate
//and its InstantiateIn = @__BuildControl__control9
@__ctrl.ItemTemplate = new System.Web.UI.CompiledBindableTemplateBuilder(
    new System.Web.UI.BuildTemplateMethod(this.@__BuildControl__control9),
    new System.Web.UI.ExtractTemplateValuesMethod(this.@__ExtractValues__control9));

//and @__BuildControl__control9 calling @__BuildControlButton1
private global::System.Web.UI.WebControls.Button @__BuildControlButton1()
{
    global::System.Web.UI.WebControls.Button @__ctrl;

    @__ctrl = new global::System.Web.UI.WebControls.Button();
    this.Button1 = @__ctrl;
    @__ctrl.ApplyStyleSheetSkin(this);
    @__ctrl.ID = "Button1"; //<-- here it gets an ID
    @__ctrl.Text = "Button";
    return @__ctrl;
}
于 2009-04-01T20:17:57.660 回答