2009-04-08 14 views
8

Mam stronę wzorcową zagnieżdżoną na 2 poziomach. Ma stronę wzorcową, a strona wzorcowa ma stronę wzorcową.Wyszukiwanie elementów sterujących wewnątrz zagnieżdżonych stron wzorcowych

Kiedy trzymać kontrole w ContentPlaceHolder o nazwie „BCR” - mam na znalezienie elementów sterujących tak:

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

jestem całkowicie zagubiony? A może tak trzeba to zrobić?

Mam zamiar pracować z MultiView, który jest wewnątrz warunkowej kontroli treści. Więc jeśli chcę zmienić widok, muszę uzyskać odniesienie do tej kontroli, prawda? Zdobycie tego odniesienia będzie jeszcze bardziej przykre! Czy istnieje lepszy sposób?

Dzięki

Odpowiedz

4

Po pierwsze, należy wiedzieć, że MasterPages rzeczywiście siedzieć wewnątrz Pages. Tak bardzo, że zdarzenie Load strony MasterPage jest faktycznie wywoływane po zdarzeniu Load ASPX.

To oznacza, że ​​obiekt strony jest w rzeczywistości najwyższą kontrolką w hierarchii kontroli.

Zatem, wiedząc o tym, najlepszym sposobem na znalezienie jakiejkolwiek kontroli w takim środowisku zagnieżdżonym, jest napisanie funkcji rekursywnej, która przechodzi przez wszystkie elementy sterujące i elementy podrzędne, dopóki nie znajdzie tego, którego szukasz. w takim przypadku strony wzorcowe są w rzeczywistości elementami podrzędnymi kontrolki głównej strony.

dostać się do głównego obiektu strony od wewnątrz jakiejkolwiek kontroli tak:

C#:

this.Page;

VB.NET

Me.Page

uważam, że zazwyczaj, metoda kontrolki klasa FindControl() jest całkiem bezużyteczny, ponieważ środowisko jest zawsze zagnieżdżone.

Bo jeśli tak, postanowiłem użyć 3.5 nowych funkcji rozszerzenia .NET, aby rozszerzyć klasę Kontroli.

za pomocą kodu poniżej (VB.NET), powiedzmy, folderu AppCode, wszystkie kontrole będą teraz peform rekurencyjną find wywołując 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 
22

Znalezienie Kontrola jest ból, a Używam tej metody, które dostałam od CodingHorror blog dość dawno temu, za pomocą jednego modyfikacji, która zwraca null, jeśli pusty id jest przekazywana.

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

w twoim przypadku, myślę, że trzeba następujące:

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

Korzystanie z tej metody jest znacznie wygodniejsze, ponieważ nie musisz dokładnie wiedzieć, gdzie znajduje się kontrola, aby ją znaleźć (oczywiście zakładając, że znasz identyfikator), ale jeśli masz zagnieżdżone formanty to samo imię, prawdopodobnie dostaniesz dziwne zachowanie, więc może to być coś, na co trzeba uważać.

+0

To działa idealnie. Dzięki. –

+0

+1 dzięki temu również mi pomogło – leen3o

+0

+1 Wiem, że to jest jak 5 lat, ale ta metoda uratowała mi trochę bólu głowy, dzięki! – psoshmo

4

Mimo że uwielbiam rekursję i zgadzam się z Andym i Munem, jeszcze jednym podejściem, które warto rozważyć, jest uzyskanie strongly typed Master page. Wszystko, co musisz zrobić, to dodać jedną dyrektywę na swojej stronie aspx.

Zamiast dostępu do kontrolki strony ze strony wzorcowej, należy rozważyć uzyskanie dostępu do kontrolki na stronie wzorcowej z samej strony. Takie podejście ma wiele sensu, gdy masz etykietę nagłówka na stronie wzorcowej i chcesz ustawić jej wartość na każdej stronie, która używa wzorca.

Nie jestem w 100% pewny, ale myślę, że byłaby to prostsza technika z zagnieżdżonymi stronami wzorcowymi, tak jak właśnie wskażesz ścieżkę VirtualPath do mastera zawierającego kontrolkę, do której chcesz uzyskać dostęp. Może to być trudne, jeśli chcesz uzyskać dostęp do dwóch kontrolek, po jednej na każdej odpowiedniej stronie wzorcowej.

+0

Tak, dobry punkt. Czasami jest to dobre, aby umieścić tę funkcję w jakiejś metodzie lub właściwości w niestandardowej bazie strony. Chociaż oczywiście nie zaszkodzi wbudować rekursywne lokalizatory kontroli – andy

1

Użyłem metody <%@ MasterType VirtualPath="~/MyMaster.master" %>. Mam właściwość na głównej stronie wzorcowej, a następnie na stronie głównej szczegółów inna właściwość o tej samej nazwie, która wywołuje główną właściwość główną i działa poprawnie.

mam to w głównej głównej stronie

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


    } 

to tylko element div, które mają pokazać się komunikat o błędzie. Chciałbym użyć tej samej właściwości na stronach ze stroną główną szczegółów (jest to zagnieżdżone z głównym wzorcem).

Następnie w szczegółach pana mam to

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

    } 

Im nazywając główną właściwość master z szczegółowo mistrza tworzyć takie samo zachowanie.

0

Po prostu działało idealnie.

W contentpage.aspx, napisałem co następuje:

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

2

Oto kod, który jest bardziej ogólny i współpracuje ze stanu niestandardowego (który może być wyrażenie lambda!)

zadzwoń:

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

rozszerzenie sterowania

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; 
    } 
} 
Powiązane problemy