Подтвердить что ты не робот

ASP.Net FindControl не работает. Почему?

Я использовал FindControl в прошлом, до .NET 2.0/3.0. Похоже, что теперь по какой-то причине идентификатор моих элементов управления получает фанки с именем, назначенным. Например, я установил флажок "cbSelect", но FindControl его не нашел. Когда я просматриваю HTML, ему присваивается ctl00_bodyPlaceHolder_ctl02_cbSelect.

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

Итак, я что-то делаю неправильно? Изменилось ли .Net? Может ли кто-нибудь пролить свет на это для меня, это действительно расстраивает!

4b9b3361

Ответ 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, где вы должны использовать идентификатор в исходной разметке.