Найти элементы внутри вложенных мастер-страниц


У меня есть главная страница, которая вложена в 2 уровня. У него есть главная страница, и эта главная страница имеет главную страницу.

Когда я вставляю элементы управления в ContentPlaceHolder с именем "bcr" - я должен найти элементы управления следующим образом:

 Label lblName =(Label)Master.Master.FindControl("bcr").FindControl("bcr").FindControl("Conditional1").FindControl("ctl03").FindControl("lblName");

Неужели я совсем потерялся? Или это то, как это должно быть сделано?

Я собираюсь работать с Мультивидом, который находится внутри условного элемента управления содержимым. Итак, если я хочу изменить представление, я должен получить ссылку на этот элемент управления, верно? Получение ссылка будет еще противнее! Есть ли лучший способ?

Спасибо

6   8   2009-04-08 05:15:22

6 ответов:

Во-первых, вы должны знать, что мастер-страницы на самом деле находятся внутри страниц. Настолько, что событие загрузки MasterPage фактически вызывается после события загрузки вашего ASPX.

Это означает, что объект Page фактически является высшим элементом управления в иерархии элементов управления. Таким образом, зная это, лучший способ найти любой элемент управления в такой вложенной среде-написать рекурсивную функцию, которая циклически проходит через каждый элемент управления и дочерние элементы управления, пока не найдет тот, который вы ищете. в этом деле, ваши мастер-страницы на самом деле являются дочерними элементами управления главной страницы.

Вы попадаете на главную страницу объекта из любого элемента управления, как это:

C#:

Это.Страница;

VB.NET

Я.Страница

Я нахожу, что обычно метод класса Findcontrol () элемента управления довольно бесполезен, так как среда всегда вложена.

Потому что в этом случае я решил использовать новые возможности расширения .NET 3.5 для расширения класса Control.

С помощью кода ниже (VB.NET), скажем, в папке AppCode все ваши элементы управления теперь будут формировать рекурсивный поиск, вызывая FindByControlID ()

    Public Module ControlExtensions
    <System.Runtime.CompilerServices.Extension()> _
    Public Function FindControlByID(ByRef SourceControl As Control, ByRef ControlID As String) As Control
        If Not String.IsNullOrEmpty(ControlID) Then
            Return FindControlHelper(Of Control)(SourceControl.Controls, ControlID)
        Else
            Return Nothing
        End If
    End Function

    Private Function FindControlHelper(Of GenericControlType)(ByVal ConCol As ControlCollection, ByRef ControlID As String) As Control
        Dim RetControl As Control

        For Each Con As Control In ConCol
            If ControlID IsNot Nothing Then
                If Con.ID = ControlID Then
                    Return Con
                End If
            Else
                If TypeOf Con Is GenericControlType Then
                    Return Con
                End If
            End If

            If Con.HasControls Then
                If ControlID IsNot Nothing Then
                    RetControl = FindControlByID(Con, ControlID)
                Else
                    RetControl = FindControlByType(Of GenericControlType)(Con)
                End If

                If RetControl IsNot Nothing Then
                    Return RetControl
                End If
            End If
        Next

        Return Nothing
    End Function

End Module

Поиск элементов управления-это боль, и я использую этот метод, который я получил из блогаCodingHorror довольно давно, с одной модификацией, которая возвращает null, если пустой идентификатор передается.

/// <summary>
/// Recursive FindControl method, to search a control and all child
/// controls for a control with the specified ID.
/// </summary>
/// <returns>Control if found or null</returns>
public static Control FindControlRecursive(Control root, string id)
{
    if (id == string.Empty)
        return null;

    if (root.ID == id)
        return root;

    foreach (Control c in root.Controls)
    {
        Control t = FindControlRecursive(c, id);
        if (t != null)
        {
            return t;
        }
    }
    return null;
}

В вашем случае, я думаю, вам понадобится следующее:

Label lblName = (Label) FindControlRecursive(Page, "lblName");

Использование этого метода, как правило, гораздо удобнее, так как вам не нужно точно знать, где находится элемент управления, чтобы найти его (предполагая, что вы знаете идентификатор, конечно), хотя если у вас есть вложенные элементы управления с то же самое имя, вы, вероятно, получите какое-то странное поведение, так что это может быть что-то, чтобы остерегаться.

Хотя я люблю рекурсию и согласен с Энди и Муном, еще один подход, который вы можете рассмотреть, - это иметь строго типизированную главную страницу. Все, что вам нужно сделать, это добавить одну директиву на страницу aspx.

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

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

Вот код, который является более универсальным и работает с пользовательским условием (это может быть лямбда-выражение!)

Вызов:

Control founded = parent.FindControl(c => c.ID == "youdId", true);

Расширение управления

 public static class ControlExtensions
{
    public static Control FindControl(this Control parent, Func<Control, bool> condition, bool recurse)
    {
        Control founded = null;
        Func<Control, bool> search = null;
        search = c => c != parent && condition(c) ? (founded = c) != null :
                                                    recurse ? c.Controls.FirstOrDefault(search) != null :
                                                    (founded = c.Controls.FirstOrDefault(condition)) != null;
        search(parent);
        return founded;
    }
}

Я использовал метод <%@ MasterType VirtualPath="~/MyMaster.master" %>. У меня есть свойство на главной главной странице, а затем на главной странице подробностей другое свойство с тем же именем, вызывающее главное главное свойство, и оно работает нормально.

У меня есть это на главной главной странице

 public string MensajeErrorString
    {
        set
        {
            if (value != string.Empty)
            {
                MensajeError.Visible = true;
                MensajeError.InnerHtml = value;
            }
            else
                MensajeError.Visible = false;
        }


    }

Это просто элемент div, который должен показывать сообщение об ошибке. Я хотел бы использовать это же свойство на страницах с главной страницей detail (она вложена в главную страницу).

Тогда в деталях мастер у меня есть это

  public string MensajeErrorString
    {
        set
        {
                Master.MensajeErrorString = value;
        }

    }

Я вызываю свойство main master из detail master, чтобы создать такое же поведение.

Я просто заставил его работать идеально.

In contentpage.aspx, я написал следующее:

If Master.Master.connectsession.IsConnected Then my coded comes in here End If