2009-04-08 14 views
8

Ho una pagina principale che è nidificata su 2 livelli. Ha una pagina principale e quella pagina master ha una pagina principale.Ricerca di controlli all'interno di pagine master nidificate

Quando ho bastone controlli in un ContentPlaceHolder con il nome "BCR" - devo trovare i controlli in questo modo:

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

Perchè sono totalmente perso? O è così che deve essere fatto?

Sto per lavorare con un MultiView, che si trova all'interno di un controllo di contenuto condizionale. Quindi se voglio cambiare la vista devo ottenere un riferimento a quel controllo, giusto? Ottenere quel riferimento sarà ancora più brutto! C'è un modo migliore?

Grazie

risposta

4

primo luogo, si dovrebbe sapere che in realtà MasterPages siedono all'interno delle pagine. Tanto che l'evento Load di MasterPage viene effettivamente chiamato dopo l'evento Load dell'ASPX.

Ciò significa che l'oggetto Pagina è in realtà il controllo più alto nella gerarchia di controllo.

Quindi, sapendo questo, il modo migliore per trovare qualsiasi controllo in tale ambiente annidato, è scrivere una funzione ricorsiva che scorre attraverso ogni controllo e controllo figlio fino a trovare quello che stai cercando. in questo caso, le tue MasterPages sono in realtà controlli figlio del controllo Pagina principale.

Si arriva all'oggetto pagina principale dall'interno alcun controllo in questo modo:

C#:

this.Page;

VB.NET

Me.Page

Trovo che di solito, il metodo di controllo della classe FindControl() è abbastanza inutile, come l'ambiente è sempre annidato.

Perché se così fosse, ho deciso di utilizzare le 3.5 nuove estensioni di .NET per estendere la classe Control.

Utilizzando il codice qui sotto (VB.NET), nel dire, la cartella AppCode, tutti i controlli saranno ora peform un ritrovamento ricorsiva chiamando 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

Trovare controlli è un dolore, e Sto usando questo metodo che ho ricevuto dal CodingHorror blog parecchio tempo fa, con una sola modifica che restituisce null se un id vuoto viene passato.

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

nel tuo caso, credo che avresti bisogno il seguente:

L'utilizzo di questo metodo è in genere molto più comodo, in quanto non è necessario sapere esattamente dove si trova il controllo per trovarlo (presumendo che si conosca l'ID, ovviamente), anche se si dispone di controlli annidati con stesso nome, probabilmente avrai un comportamento strano, quindi potrebbe essere qualcosa a cui prestare attenzione.

+0

Questo funziona perfettamente. Grazie. –

+0

+1 grazie anche questo mi ha aiutato – leen3o

+0

+1 so che questo è come 5 anni, ma questo metodo mi ha salvato un po 'di mal di testa, grazie! – psoshmo

4

Anche se amo la ricorsione e sono d'accordo con andy e Mun, un altro approccio che si potrebbe prendere in considerazione è di avere un strongly typed Master page. Tutto quello che devi fare è aggiungere una direttiva nella tua pagina aspx.

Invece di accedere al controllo di una pagina dalla pagina principale, prendere in considerazione l'accesso a un controllo nella pagina principale dalla pagina stessa. Questo approccio ha molto senso quando si ha un'etichetta di intestazione nella pagina principale e si desidera impostare il suo valore da ciascuna pagina che utilizza il master.

Non sono sicuro al 100%, ma penso che sarebbe una tecnica più semplice con le pagine master annidate, come si farebbe semplicemente puntare il VirtualPath sul master contenente il controllo a cui si desidera accedere. Potrebbe rivelarsi complicato se si desidera accedere a due controlli, uno in ciascuna rispettiva pagina principale.

+0

sì, buon punto. A volte è utile solo mettere tale funzionalità in qualche tipo di metodo o proprietà nella propria base di pagine personalizzate. Anche se, naturalmente, non fa male avere dei rilevatori di controllo ricorsivi – andy

1

Ho utilizzato il metodo <%@ MasterType VirtualPath="~/MyMaster.master" %>. Ho una proprietà nella pagina principale principale, quindi nella pagina principale dettaglio un'altra proprietà con lo stesso nome che chiama la proprietà principale principale e funziona correttamente.

ho questo nel master pagina principale

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


    } 

questo è solo un elemento div che devono mostrare un messaggio di errore. Vorrei usare questa stessa proprietà nelle pagine con la pagina principale dei dettagli (questa è annidata con il master principale).

Poi nel master dettaglio che hanno questo

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

    } 

Im chiamando la proprietà principale master dal maestro dettagli per creare lo stesso comportamento.

0

Ho appena funzionato perfettamente.

In contentpage.aspx, ho scritto il seguente:

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

2

Qui è un codice che è più generico e funziona con una condizione personalizzato (che può essere un'espressione lambda!)

Chiama:

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

estensione di controllo

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