以编程方式添加的 TemplateField 中的控件何时具有其“ ID属性设置?
我有一个动态添加到自定义 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 均为 null - 尽管如上所述,仅读取前两个将触发所有设置。 另请注意,NamingContainer 不为空。 已经设定了。
因此,解决这个问题的方法非常简单,即检查 ctrl.ID==null,如果是,则只需读取 ctrl.ClientID。 这就是我所做的,因为从时间角度来看,我真的必须继续努力。 但如果有人立即知道答案,我仍然对答案感兴趣。
为什么动态添加的 TemplateField 的子控件的 ID 值设置时间与其他控件的 ID 值不同?
I have a TemplateField that is dynamically added to a custom GridView.
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;
}
}
In response to a grid Command (insert/update/delete), a method called GetRowControls is called which iterates through the columns in the particular gridrow, and adds each of its controls to a Dictionary.
Dictionary<string, WebControl> GetRowControls(GridViewRow row)
...
rowControls.Add(ctrl.ID, (WebControl)ctrl);
...
So this works fine for both template field and bound controls added declaratively, as well as dynamic-non template fields added programatically.
However when the control is a TemplateField control added dynamically ctrl.ID is always null and therefore the statement above throws an exception.
I've looked into this with Reflector because I found that when I examined the variable in the immediate window in VS 2005 i.e. ?ctrl, ctrl.ID WOULD list a value. I've since established that this is because in listing ?ctrl in the immediate window, the proprty ClientID is called and ClientID calls EnsureId(), which in turn sets 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;
}
}
So I'm assuming that ClientID, UniqueId and ID are all null - although as above just reading the first two will trigger all to be set. Also note that NamingContainer is not null. It has been set.
So the work around for this is quite simple i.e. check for ctrl.ID==null and if so simply read ctrl.ClientID. And thats what I've done because time wise I've really got to get a wriggle on. But I'm still interested in the answer if anyone knows it off the top of their heads.
Why is the ID value of a child control, of a dynamically added TemplateField, set at a different time from that of other controls?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这并不是说它们的行为不同,而是当您以声明方式添加控件时,几乎总是会立即设置 ID。 尝试向页面添加一个没有 ID 的标签,然后浏览控件集合并检查其 ID,它将为空(确保不要显示其 clientID,因为它会填充 ID):
另请注意,如果您像这样运行它你会得到一个没有 ID 的跨度。
It is not that they behave differently, but that almost always when you add a control declaratively you set the ID right away. Try adding a label with no ID to a page and browse the control collection and check its ID, it will be null (make sure not to show its clientID since it would get the ID filled):
Also note that if you run it like that you get an span with no ID.
弗雷迪是对的。
您负责在 InstantiateIn 方法内设置 ID。 如果没有另外指定,ClientID 会自动生成它们,这是有道理的。
声明性控件在页面编译期间获取由页面构建器分配的 ID。 如果您要查看“临时 ASP.NET 文件文件夹”中生成的临时 .cs 文件之一,您会发现类似以下内容(已删除编译指示):
Freddy is correct.
Your are responsible for setting IDs inside the InstantiateIn method. And it makes sense that ClientID auto-generates them if not specified otherwise.
The declarative controls get their IDs assigned by a page builder during compilation of a page. If you were to look at one of temp .cs files generated in the "Temporary ASP.NET Files folder", you'd find something like this (pragmas stripped):