2011-01-12 16 views
9

Ho diverse caselle di testo in una winform, alcune di loro sono all'interno di una groupbox. Ho cercato di loop su tutte le caselle di testo in mia forma:loop su tutte le caselle di testo in un modulo, comprese quelle all'interno di una groupbox

For Each c As Control In Me.Controls 
    If c.GetType Is GetType(TextBox) Then 
     ' Do something 
    End If 
Next 

ma sembrava di ignorare quelli all'interno della GroupBox e ciclo unico sulle altre caselle di testo della forma. Così ho aggiunto un altro ciclo For Each per le caselle di testo GroupBox:

For Each c As Control In GroupBox1.Controls 
    If c.GetType Is GetType(TextBox) Then 
     ' Do something 
    End If 
Next 

mi chiedo: c'è un modo per ciclo su tutte le caselle di testo in una forma - compresi quelli all'interno di un GroupBox - con un unico ciclo For Each? O un modo migliore/più elegante per farlo?

Grazie in anticipo.

+0

Eventuali duplicati di [Come ottenere tutti i controlli figlio di un Windows Form forma di un tipo specifico (Pulsante/casella di testo)?] (Https://stackoverflow.com/questions/3419159/how-to-get -ALL-bambini-controlli-di-un-windows-forme-forma-di-un-tipo specifico pulsante) – PulseJet

risposta

17

È possibile utilizzare questa funzione, linq potrebbe essere un modo più elegante.

Dim allTxt As New List(Of Control) 
For Each txt As TextBox In FindControlRecursive(allTxt, Me, GetType(TextBox)) 
    '....' 
Next 

Public Shared Function FindControlRecursive(ByVal list As List(Of Control), ByVal parent As Control, ByVal ctrlType As System.Type) As List(Of Control) 
    If parent Is Nothing Then Return list 
    If parent.GetType Is ctrlType Then 
     list.Add(parent) 
    End If 
    For Each child As Control In parent.Controls 
     FindControlRecursive(list, child, ctrlType) 
    Next 
    Return list 
End Function 
1

che ci si vuole fare ricorsione, per esempio (pseudocodice, dal momento che non so VB):

Sub LoopControls (Control Container) 
    if (Container has Controls) 
     LoopControls(Container) 
    For Each c As Control In Container 
     if (Control is TextBox) 
      // do stuff 
End Sub 

si farebbe passare il modulo (me) al sub inizialmente, e sarà attraversare i controlli in esso alla ricerca di quelli che contengono più controlli.

controllare anche questa domanda: VB.NET - Iterating through controls in a container object

0

È necessario utilizzare la ricorsione. La seguente è una soluzione C# che usa un metodo di estensione e va un po 'oltre la portata della tua domanda, ma l'ho appena estratta dal nostro framework.

static partial class ControlExtensions 
{ 
    public static void ApplyToMatchingChild(this Control parent, Action<Control> actionToApplyWhenFound, bool keepApplyingForever, params Func<Control, bool>[] matchingChildCriteria) 
    { 
     ControlEventHandler reapplyEventHandler = null; 
     if (keepApplyingForever) 
     { 
      reapplyEventHandler = (s, e) => 
      { 
       ApplyToMatchingChild(e.Control, actionToApplyWhenFound, keepApplyingForever, matchingChildCriteria); 
      }; 
     } 
     SearchForMatchingChildTypes(parent, actionToApplyWhenFound, reapplyEventHandler, matchingChildCriteria); 
    } 

    private static void SearchForMatchingChildTypes(Control control, Action<Control> actionToApplyWhenFound, ControlEventHandler reapplyEventHandler, params Func<Control, bool>[] matchingChildCriteria) 
    { 
     if (matchingChildCriteria.Any(criteria => criteria(control))) 
     { 
      actionToApplyWhenFound(control); 
     } 

     if (reapplyEventHandler != null) 
     { 
      control.ControlAdded += reapplyEventHandler; 
     } 

     if (control.HasChildren) 
     { 
      foreach (var ctl in control.Controls.Cast<Control>()) 
      { 
       SearchForMatchingChildTypes(ctl, actionToApplyWhenFound, reapplyEventHandler, matchingChildCriteria); 
      } 
     } 
    } 
} 

e di chiamare:

myControl.ApplyToMatchingChild(c => { /* Do Stuff to c */ return; }, false, c => c is TextBox); 

che si applica una funzione per tutte le caselle di testo per bambini. È possibile utilizzare il parametro keepApplyingForever per garantire che la funzione venga applicata quando vengono aggiunti in seguito i controlli figlio. La funzione consentirà inoltre di specificare qualsiasi numero di criteri di corrispondenza, ad esempio se il controllo è anche un'etichetta o altri criteri.

In realtà usiamo questo come un modo pulito per chiamare il nostro contenitore di iniezione dipendenza per ogni UserControl aggiunto al nostro modulo.

Sono sicuro che non dovresti avere molti problemi anche converting it to VB.NET ... Inoltre, se non vuoi la funzionalità "keepApplyingForever", dovrebbe essere abbastanza semplice da eliminare anche quella.

0

Se non ti interessa l'ordine (e non riesco a immaginare un motivo per cui dovresti) dei controlli, puoi farlo in modo iterativo nel seguente modo (è piuttosto semplice, quindi non penso qualsiasi spiegazione è necessaria). Dovrebbe essere molto più efficiente di qualsiasi ricorsione, specialmente se si hanno molti controlli annidati, anche se dubito che il guadagno in termini di prestazioni sarebbe evidente.

Public Function FindAllControlsIterative(ByRef parent As Control) As List(Of TextBox) 
    Dim list As New List(Of TextBox) 
    Dim ContainerStack As New Stack(Of Control) 
    ContainerStack.Push(parent) 
    While ContainerStack.Count > 0 
     For Each child As Control In ContainerStack.Pop().Controls 
      If child.HasChildren Then ContainerStack.Push(child) 
      If child.GetType Is GetType(TextBox) Then list.Add(child) 
     Next 
    End While 
    Return list 
End Function 
Problemi correlati