ASP.Net FindControl не работает. Почему?
Я использовал FindControl
в прошлом, до .NET 2.0/3.0. Похоже, что теперь по какой-то причине идентификатор моих элементов управления получает фанки с именем, назначенным. Например, я установил флажок "cbSelect", но FindControl его не нашел. Когда я просматриваю HTML, ему присваивается ctl00_bodyPlaceHolder_ctl02_cbSelect
.
Я не нашел один пример FindControl, который упоминает об этом. На самом деле все, кажется, просто используют управление находкой, как обычно.
Итак, я что-то делаю неправильно? Изменилось ли .Net? Может ли кто-нибудь пролить свет на это для меня, это действительно расстраивает!
Ответы
Ответ 1
Вероятно, вы используете MasterPage или пользовательские элементы управления (ascx), и это причина изменения идентификаторов клиента. Представьте, что на главной странице есть элемент управления с тем же идентификатором, что и на странице. Это приведет к столкновениям. Изменения id гарантируют, что все свойства ClientID уникальны на странице.
FindControl требует особого внимания при работе с MasterPages. Посмотрите ASP.NET 2.0 MasterPages и FindControl(). FindControl работает внутри контейнера имен . MastePage и страница представляют собой разные контейнеры с именами.
Ответ 2
У меня была удачная работа над этой проблемой в "большинстве" случаев с помощью простого метода расширения
Вы можете вызвать его на любом более высоком уровне управления контейнером, который вы считаете лучшим, в том числе самой странице, если вы хотите отсканировать всю иерархию управления.
private static Control FindControlIterative(this Control control, string id)
{
Control ctl = control;
LinkedList<Control> controls = new LinkedList<Control>();
while(ctl != null)
{
if(ctl.ID == id)
{
return ctl;
}
foreach(Control child in ctl.Controls)
{
if(child.ID == id)
{
return child;
}
if(child.HasControls())
{
controls.AddLast(child);
}
}
ctl = controls.First.Value;
controls.Remove(ctl);
}
return null;
}
Ответ 3
Вы можете написать расширитель, чтобы найти какой-либо элемент управления на странице, используя рекурсию.
Это может быть в некоторых классах Util/Helper.
public static Control FindAnyControl(this Page page, string controlId)
{
return FindControlRecursive(controlId, page.Form);
}
public static Control FindAnyControl(this UserControl control, string controlId)
{
return FindControlRecursive(controlId, control);
}
public static Control FindControlRecursive(string controlId, Control parent)
{
foreach (Control control in parent.Controls)
{
Control result = FindControlRecursive(controlId, control);
if (result != null)
{
return result;
}
}
return parent.FindControl(controlId);
}
Ответ 4
При поиске элемента управления в коллекции управления всегда используйте идентификатор, которому вы назначили элемент управления, а не тот, который вы видите в обработчике исходного сообщения. Если FindControl() не находит элемент управления, который, как вы знаете, существует, есть хороший шанс, что вы не ищете в правой ветки иерархии управления. Рекурсивная функция была успешной для меня.
Вот мой пример того, что я использую для VB.NET 3.5:
Function FindControlRecursive(ByVal ctrl As Control, ByVal id As String) As Control
Dim c As Control = Nothing
If ctrl.ID = id Then
c = ctrl
Else
For Each childCtrl In ctrl.Controls
Dim resCtrl As Control = FindControlRecursive(childCtrl, id)
If resCtrl IsNot Nothing Then c = resCtrl
Next
End If
Return c
End Function
Вот пример того, как я бы в точности реализовал эту функцию в классе базовой страницы:
Dim form HtmlForm = CType(FindControlRecursive(Me, "Form"), HtmlForm)
Ответ 5
Это код VB.NET, который работал у меня:
<Extension()> _
Function FindChildControlById(ByVal controlToStartWith As Control, ByVal controlIdToFind As String) As Control
If controlToStartWith Is Nothing Then Return Nothing
If controlToStartWith.ID = controlIdToFind Then Return controlToStartWith
For Each childControl As Control In controlToStartWith.Controls
Dim resCtrl As Control = FindChildControlById(childControl, controlIdToFind)
If resCtrl IsNot Nothing Then Return resCtrl
Next childControl
Return Nothing
End Function ' Function FindChildControlById(ByVal controlToStartWith As Control, ByVal controlIdToFind As String) As Control
Кредит отправляется Джорджу для исходного кода VB.NET. Я только модифицировал его в младшем разряде, с 2 функциональными изменениями: у меня не ошибка, если/когда null/Ничто не передается в качестве контроля ввода, а мое реализовано как расширение. Мои другие 3 незначительные изменения не влияют на функциональность, но для меня это были упрощения кода. Но я знаю, что это очень субъективно.
Таким образом, этот метод можно использовать с:
Dim c1 As Control = Page.FindChildControlById("aspControlID")
И если вы хотите преобразовать его в определенный дочерний класс элемента управления, например:
Dim c1 As Control = Page.FindChildControlById("aspControlID")
Dim c As HyperLink = TryCast(c1, HyperLink)
Обновление: теперь моя функция называется "FindChildControlById" (ранее был "FindMiControl" ). Мне понравилось предложение SpeedNet лучше.
Ответ 6
При рендеринге html ASP.NET будет префикс всех идентификаторов управления с идентификаторами контейнеров именования (User Controls и т.д.) в иерархии, полностью возвращаясь к корню документа. Это гарантирует, что все идентификаторы уникальны для post backs и т.д.
Это не влияет на использование FindControl, где вы должны использовать идентификатор в исходной разметке.
Ответ 7
Вот ссылка на то, как названы элементы управления веб-формы...
Идентификация веб-форм