直接调用ListView1.FindControl("idLable") 报个错未将对象实例内个错抱着好奇的心态我百度了下。大概有4种办法我就不说了。
其中一种办法是
Response.Write(ListView1.FindControl("ListView1$ctrl0$idLabel"));
主要问题是id变了。ID变成Control.UniqueID了。为什么会出现这种情况呢。
抱着好奇的心态我查了下msdn原来ListView实现了INamingContainer接口子控件的Control.UniqueID变成了父容器加子容器的形式了!难怪
Response.Write(ListView1.FindControl("ListView1$ctrl0$idLabel"))可以找到这个控件。现在看似问题解决了。可是还是有个问题
protected void ListView1_ItemDataBound(object sender, ListViewItemEventArgs e)
{
//这里和Repeater稍有不同
if (e.Item.ItemType == ListViewItemType.DataItem)
{
Label txtName = (Label)e.Item.FindControl("idLable");
txtName.Text = "我是ListView中被查找的子控件";
}
}
这个方法也能找到Lable不是说FindControl传的是Control.UniqueID么?这里传idLable怎么可以?经过我和狮虎仔细讨论之后终于得出了结论。
我们可以看e.Item的类型
namespace System.Web.UI.WebControls
{
// 摘要:
// 表示 System.Web.UI.WebControls.ListView 控件中的单个项。
[ToolboxItem(false)]
public class ListViewItem : Control, IDataItemContainer, INamingContainer
{
// 摘要:
// 初始化 System.Web.UI.WebControls.ListViewItem 类的新实例。
//
// 参数:
// itemType:
// System.Web.UI.WebControls.ListViewItemType 枚举值之一。
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public ListViewItem(ListViewItemType itemType);
// 摘要:
// 获取或设置 System.Web.UI.WebControls.ListViewItem 对象绑定到的基础数据对象。
//
// 返回结果:
// System.Web.UI.WebControls.ListViewItem 对象绑定到的基础数据对象。
public virtual object DataItem { get; set; }
//
// 摘要:
// 获取绑定到 System.Web.UI.WebControls.ListViewItem 控件的数据项的索引。
//
// 返回结果:
// 绑定到 System.Web.UI.WebControls.ListViewItem 控件的数据项的索引。
public virtual int DataItemIndex { get; }
//
// 摘要:
// 获取数据项在 System.Web.UI.WebControls.ListView 控件中显示的位置。
//
// 返回结果:
// 数据项在 System.Web.UI.WebControls.ListView 控件中显示的位置。
public virtual int DisplayIndex { get; }
//
// 摘要:
// 获取 System.Web.UI.WebControls.ListViewItem 对象的项类型。
//
// 返回结果:
// System.Web.UI.WebControls.ListViewItemType 值之一。
public ListViewItemType ItemType { get; }
// 摘要:
// 确定是否将事件沿页面的 ASP.NET 服务器控件层次结构向上传递。
//
// 参数:
// source:
// 事件源。
//
// e:
// 事件数据。
//
// 返回结果:
// 如果事件已被取消,则为 true;否则为 false。
protected override bool OnBubbleEvent(object source, EventArgs e);
}
}
ListViewItem继承了INamingContainer接口。好吧现在让我们理解为什么ListView1.FindControl("ldLable")不行而Label txtName = (Label)e.Item.FindControl("idLabel")可以。INamingContainer接口是让子控件的Control.UniqueID变成类似父容器加子控件的形式。而在Label txtName = (Label)e.Item.FindControl("idLabel")注意这个事件是绑定行的时候发生的也就是说e.Item就代表一行。他是idLable的上一级控件。所以Label txtName = (Label)e.Item.FindControl("idLabel")在FindControl的时候必定会先转化为Control.UniqueID!这样就不违反FindControl(Control.UniqueID)的规则了。而ListView1.FindControl("ldLable")很明显虽然ListView继承了INamingContainer但是他不是ldLable的上一级控件不是他的父容器。无法将ldLable转化成父容器加子控件的Control.UniqueID,违反了FindControl(Control.UniqueID)的规则!自然找不到。
由此我推断出了FindControl工作的大致的流程。先判断调用他的对象是否继承INamingContainer如果继承就转化为INamingContainer,将控件转化为父容器加子控件的形式.ListView1这么调用的时候 没发现他的子控件有lblable ,然后再看他本身是不是服务器ID 结果发现又不是 ,就抛出异常了.而Label txtName = (Label)e.Item.FindControl("idLabel") 的时候本身就发现idLabel是他的子控件,ListViewItem又继承了INamingContainer接口,直接转化成"ListView1$ctrl0$idLabel"这样当然找的到叻。哈哈。为了验证我的想法。我自定义了一个控件让他继承INamingContainer.
[ToolboxData("<{0}:INamingContainerControl runat=server></{0}:INamingContainerControl>")]
public class INamingContainerControl : WebControl, INamingContainer //可以将 INamingContainer 去掉, 运行并查看源代码
{
protected override void CreateChildControls()
{
TextBox textbox = new TextBox();
textbox.ID = "btn";
textbox.Text = "我是淡淡蜀黍";
this.Controls.Add(textbox);
Button button = new Button();
button.ID = "btnOK";
button.Text = "确定";
this.Controls.Add(button);
}
}
然后在html里使用这个控件
<cc1:INamingContainerControl ID="INamingContainerControl1" runat="server" />
<cc1:INamingContainerControl ID="INamingContainerControl2" runat="server" />
后台cs文件在Page_Load事件里写如下代码通过控件本身的ID搜索
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(((TextBox)(INamingContainerControl1.FindControl("btn"))).Text);
}
运行结果如图
很明显可以搜到控件。
再查看页面源html:
<div>
<span id="INamingContainerControl1"><input name="INamingContainerControl1$btn" type="text" value="我是淡淡蜀黍" id="INamingContainerControl1_btn" /><input type="submit" name="INamingContainerControl1$btnOK" value="确定" id="INamingContainerControl1_btnOK" /></span>
<span id="INamingContainerControl2"><input name="INamingContainerControl2$btn" type="text" value="我是淡淡蜀黍" id="INamingContainerControl2_btn" /><input type="submit" name="INamingContainerControl2$btnOK" value="确定" id="INamingContainerControl2_btnOK" /></span>
</div>
很明显ID是父容器加子控件的形式的。这说明如果搜索的调用者也就是control.FindControl(string id)的这个control是子控件的父容器且继承了INamingContainer接口完全可以通过编程是定义的ID通过FindControl搜到控件上面的推论完全成立。。问题终于解决叻。嘎嘎。