我正在动态创建数据绑定DropDownList控件并将其添加到数据绑定器Repeater控件中的占位符,该控件是放置在带有选项卡的页面上的自定义用户控件。
DropDownList的Id是动态设置的,对于下面生成的HTML,它是Comp1A
控件创建和使用工作正常,但是当我尝试递归地找到控件时,我总是变为null。
以下是生成的HTML:
<select class="formDropDownRating" id="MainContent_ContentPlaceHolder1_TabContainer1_tab1_CE1_Repeater1_Comp1A_0" name="ctl00$ctl00$MainContent$ContentPlaceHolder1$TabContainer1$tab1$CE1$Repeater1$ctl00$Comp1A">
<option value="5">5 - Strongly Agree</option>
<option value="4">4 - Agree</option>
<option value="3">3 - Somewhat Agree</option>
<option value="2">2 - Disagree</option>
<option value="1">1 - Strongly Disagree</option>
</select>
找到我正在调用的控件
target = FindDropDownListControl("Comp1A");
与
见Jeff Atwood的function
protected DropDownList FindDropDownListControl(string controlReference)
{
Control root = this.Page.FindControl("ctl00"); //the Master page (the root control)
var ddl = (DropDownList)MyApp.Utility.ExtensionMethods.FindControlRecursive(root, controlReference) as DropDownList;
return ddl;
}
有人能发现可能是罪魁祸首吗?我怎样才能获得对Comp1A的引用?
答案 0 :(得分:1)
我不是百分百肯定,因为您的代码示例不包含控件的创建方式,但如果我的怀疑是正确的,问题是控件是在页面生命周期中的某个位置创建的在回发中消失了。
确切地说,页面生命周期中的控件是创建?如果它没有在正确的位置创建,或者在循环中太晚,那么它将不会保留在回发中的Viewstate中。
如果可能,请确保在Page_Init中创建它,或者手动将其添加到Page_Init。
This article更全面地解释了这一点。
答案 1 :(得分:0)
您应该始终尝试使用最靠近控件的容器作为根。如果您可以访问转发器或转发器项,则将其用作根。
如果您无法访问转发器,请尝试使用页面或表单作为根目录:
protected DropDownList FindDropDownListControl(string controlReference)
{
var ddl = (DropDownList)MyApp.Utility.ExtensionMethods.FindControlRecursive(Page, controlReference) as DropDownList;
return ddl;
}
答案 2 :(得分:0)
我觉得它看起来像那样,
public static T FindControl<T>(this Control control) {
T ctrl = default(T);
if(control == null) return null;
foreach(Control c in control.Controls) {
if(ctrl == null) {
ctrl = FindControl<T>(c);
}
else return ctrl;
}
}
我没有测试过,但您可以根据需要进行测试。
btw :如果我没记错的话,你需要在PageLoad事件后使用它吗OnPreRender
比你能看到结果。
最诚挚的问候。
答案 3 :(得分:0)
编辑:我的猜测是你的页面中有一些其他控件也有ID“Comp1A”,并且你的FindControlRecursive
方法首先找到该控件。它可能会给你null,因为无论它是什么控件都不是DropDownList。执行as DropDownList
时,结果将为null。
以下是我对FindControl
的了解,如果这对您有任何帮助。
FindControl仅限于同一命名容器中的控件(即实现INamingContainer接口的Parent / Ancestor控件)。如果您正在尝试查找位于另一个控件内部的控件,该控件是相对于您调用FindControl
方法的控件的命名容器,则它将无法找到它。
Page是一个命名容器,UserControl和ContentPlaceHolder也是如此。我认为TabContainer也是一个命名容器,以及TabContainer中的每个选项卡控件。
EDIT2:Repeater和RepeaterItem(转发器的每个“行”都是RepeaterItem)也都是命名容器。这意味着如果从顶部(即页面)开始查看,您实际上无法可靠地找到嵌套在转发器中的控件。你需要在同一个RepeaterItem中设置你的起点(基本上这就是詹姆斯约翰逊所建议的)。如果您需要更多帮助,那么您需要提供有关执行target = FindDropDownListControl("Comp1A");
的上下文的更多信息。
您的代码从页面开始,并尝试深入查找“Comp1A”DropDownList。如果此控件只是“CE1”用户控件中的正常控件,那么您可以使用以下内容找到它:
this.Master.Master.FindControl("MainContent").FindControl("ContentPlaceHolder1").FindControl("TabContainer1").FindControl("tab1").FindControl("CE1").FindControl("Comp1A")
(哎呀!太长了。请参阅下面的更短语法。)
母版页也充当命名容器,这就是我开始使用this.Master
而不是this.Page
的原因。
您似乎在另一个母版页中使用母版页,因此我更新了我的示例以使用this.Master.Master
。
根据Jeff的帖子,你可以使用以下语法完成同样的事情:
this.Master.Master.FindControl("MainContent:ContentPlaceHolder1:TabContainer1:tab1:CE1:Comp1A")
但是,如上所述,您尝试查找的控件位于转发器内部。您可以做的一件事是迭代转发器中的所有项目,如下所示:
Control repeater = this.Master.Master.FindControl("MainContent:ContentPlaceHolder1:TabContainer1:tab1:CE1:Repeater1");
foreach (Control control in repeater.Controls)
{
var button = control.FindControl("Comp1A");
}
但是如果您正在从转发器的特定行中寻找一个特定的“Comp1A”DropDownList控件,那么您需要利用您的上下文来为您的搜索使用正确的根控件。