FindControl не работает для динамически созданного пользовательского элемента управления - PullRequest
1 голос
/ 16 ноября 2011

Я динамически создаю элемент управления DropDownList с привязкой к данным и добавляю его в заполнитель в элементе управления Repeater с привязкой к данным, который представляет собой пользовательский элемент управления, размещенный на странице с вкладками.

Идентификатор DropDownList устанавливается динамически, идля сгенерированного HTML ниже это Comp1A

Создание и использование элемента управления работает нормально, но когда я пытаюсь найти элемент управления рекурсивно, я всегда получаю нулевое значение.

Вот сгенерированный 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");

с

см. функцию Джеффа Этвуда

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?

Ответы [ 4 ]

1 голос
/ 16 ноября 2011

Я не уверен на 100%, потому что в примерах кода не указано, как создаются элементы управления, но если мои подозрения верны, проблема заключается в том, что элемент управления создается в той точке жизненного цикла страницы, где он стирается с обратной передачи.

Где именно находится элемент управления , созданный в жизненном цикле страницы? Если он не был создан в нужном месте или слишком поздно в цикле, то он не будет сохранен в Viewstate на обратной передаче.

Если возможно, убедитесь, что он создается в Page_Init, или добавьте его вручную в Page_Init.

Эта статья объясняет это более полно.

0 голосов
/ 16 ноября 2011

EDIT: я предполагаю, что у вас есть другой элемент управления на вашей странице, который также имеет идентификатор "Comp1A", и что ваш FindControlRecursive метод сначала находит этот элемент управления.Вероятно, он дает вам нулевое значение, потому что этот элемент управления, каким бы он ни был, не является DropDownList.Когда вы делаете as DropDownList, в этом случае результат будет нулевым.

Вот что я знаю о FindControl, на случай, если это вам чем-то поможет.

FindControl ограничендля элементов управления в том же контейнере именования (т.е. элемент управления Parent / Ancestor, который реализует интерфейс INamingContainer).Если вы пытаетесь найти элемент управления, который находится внутри другого элемента управления, который является контейнером именования относительно элемента управления, для которого вы вызываете метод FindControl, он не найдет его.

A Страницаявляется контейнером именования, как 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")

(Yikes! Это слишком долго. Более короткий синтаксис приведен ниже.)

Мастер-страница также выступает в качестве контейнера именования, поэтому я начал с this.Master вместо this.Page.

Похоже, вы используете мастер-страницу в другом мастерепоэтому я обновил свой пример, чтобы использовать this.Master.Master.

Согласно сообщению Джеффа, вы можете выполнить то же самое, используя следующий синтаксис:

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 из определенной строки повторителя, товам нужно будет использовать свой контекст, чтобы использовать правильный корневой элемент управления для поиска.

0 голосов
/ 16 ноября 2011

Я думаю, что это выглядит примерно так,

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;
    }
}

Я не проверял его, но вы можете сравнить пример с вашими потребностями.

кстати : вам нужно использовать его после события PageLoad, если я правильно помню, что это OnPreRender
чем вы сможете увидеть результат. С наилучшими пожеланиями.

0 голосов
/ 16 ноября 2011

Вы всегда должны использовать контейнер, ближайший к элементу управления, в качестве корневого.Если вы можете получить доступ к повторителю или элементу повторителя, используйте его в качестве корня.

Если вы не можете получить доступ к повторителю, попробуйте использовать страницу или форму в качестве корня:

protected DropDownList FindDropDownListControl(string controlReference) 
{ 
    var ddl = (DropDownList)MyApp.Utility.ExtensionMethods.FindControlRecursive(Page, controlReference) as DropDownList;  
    return ddl; 
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...