2009-04-28 9 views
27

Ho utilizzato FindControl in passato, prima di .NET 2.0/3.0. Sembra che ora, per qualche motivo, gli ID dei miei controlli abbiano un nome funky assegnato. Ad esempio, ho assegnato un ID "cbSelect" a una casella di controllo, ma FindControl non lo trova. Quando visualizzo l'HTML è stato assegnato ctl00_bodyPlaceHolder_ctl02_cbSelect.ASP.Net FindControl non funziona - Come mai?

Non ho trovato un esempio di FindControl che lo menzioni. In effetti tutti sembrano usare il controllo di ricerca come al solito.

Quindi, sto facendo qualcosa di sbagliato? .Net è cambiato? Qualcuno può far luce su questo per me, è davvero frustrante!

risposta

25

Probabilmente stai usando un MasterPage o controlli utente (ascx) e questo è il motivo per cui cambiano gli ID cliente. Immagina di avere un controllo nella pagina principale con lo stesso id di uno nella pagina. Ciò comporterebbe scontri. Le modifiche all'ID assicurano che tutte le proprietà ClientID siano univoche in una pagina.

FindControl necessita di particolare attenzione quando si lavora con MasterPages. Dai un'occhiata a ASP.NET 2.0 MasterPages and FindControl(). FindControl funziona all'interno di un naming container. MastePage e la pagina sono contenitori di denominazione diversi.

+9

Il modo in cui Microsoft ha implementato questo è uno scherzo, dovrebbe funzionare. Oh hai una masterpage? Che ne dici di 500 pagine master annidate? Il metodo dovrebbe capirlo e fare ciò che è necessario per trovare il controllo, punto. –

+0

Sai che stai usando "dovrebbe" e "Microsoft" nello stesso pensiero? – user1566694

1

Quando esegue il rendering dell'HTML, ASP.NET prefixerà tutti gli ID di controllo con gli ID dei contenitori di denominazione (Controlli utente, ecc.) In una gerarchia che risale alla radice del documento. Ciò garantisce che tutti gli ID siano unici per i postback ecc.

Questo non ha effetto sull'uso di FindControl in cui è necessario utilizzare l'ID nel markup originale.

8

che ho avuto abbastanza buona fortuna a lavorare intorno a questo problema nella "maggior parte dei" casi con un semplice metodo di estensione

È possibile chiamarlo su qualsiasi controllo contenitore di livello superiore che si ritiene migliore, inclusa la Pagina stessa se si desidera eseguire la scansione dell'intera gerarchia di controlli.

8

È possibile scrivere extender per trovare qualsiasi controllo sulla pagina utilizzando la ricorsione. Questo potrebbe essere in alcune classi 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); 
    } 
7

Durante la ricerca di un controllo in una raccolta di controllo, utilizzare sempre l'id è stato assegnato il controllo, non quella che vedete nel post fonte rendering. Se FindControl() non trova il controllo che si conosce esiste, ci sono buone probabilità che non si stia cercando nel ramo destro della gerarchia di controllo. Una funzione ricorsiva ha avuto successo per me.

Ecco il mio esempio di quello che io uso per 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 

Ecco un esempio di come avrei implementare localmente questa funzione nella mia classe pagina di base:

Dim form HtmlForm = CType(FindControlRecursive(Me, "Form"), HtmlForm) 
+1

+1 perché senza vederlo l'avevo già implementato in C# con lo stesso approccio: 'statico pubblico System.Web.UI.Control FindControlRecursive (controllo ctl, id stringa) {' if (ctl == null) ritorno nullo; if (ctl.ID == id) return ctl; if (ctl.Controls.Count> 0) foreach (Controllo sc in ctl.Controls) { Controllo fnd = FindControlRecursive (sc, id); if (fnd! = Null) return fnd; } return null; } ' – gkakas

3

Questo è il VB.Codice NET che ha funzionato per me:

<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 

Il credito va a George per il codice VB.NET iniziale. L'ho modificato solo un po ', con 2 modifiche funzionali: il mio non ha errori se/quando null/Nothing è passato come controllo di input, e il mio è implementato come estensione. Le mie altre 3 modifiche minori non influiscono sulla funzionalità, ma per me sono state semplificazioni del codice. Ma so che è molto soggettivo.

Quindi questo metodo può essere utilizzato con:

Dim c1 As Control = Page.FindChildControlById("aspControlID") 

E se si desidera convertire in una specifica classe di figlio di un controllo, in questo modo:

Dim c1 As Control = Page.FindChildControlById("aspControlID") 
Dim c As HyperLink = TryCast(c1, HyperLink) 

Aggiornamento: La mia funzione è ora chiamato 'FindChildControlById' (precedentemente era 'FindMiControl'). Mi è piaciuto il suggerimento di SpeedNet meglio.

+0

Questo è perfetto, meglio delle altre soluzioni, grazie! Ho rinominato FindChildControlByID(). – Speednet