2011-09-09 41 views

回答

50

檢查my previous SO answer

基本上,這個想法是包裹使用通過控制集合迭代的遞推:

private void GetControlList<T>(ControlCollection controlCollection, List<T> resultCollection) 
where T : Control 
{ 
    foreach (Control control in controlCollection) 
    { 
     //if (control.GetType() == typeof(T)) 
     if (control is T) // This is cleaner 
      resultCollection.Add((T)control); 

     if (control.HasControls()) 
      GetControlList(control.Controls, resultCollection); 
    } 
} 

和使用它:

List<DropDownList> allControls = new List<DropDownList>(); 
GetControlList<DropDownList>(Page.Controls, allControls) 
foreach (var childControl in allControls) 
{ 
//  call for all controls of the page 
} 

[編輯2013年11月26日] :這是達到這個目標的更優雅的方式。我寫了兩個可以在兩個方向上走控制樹的擴展方法。這些方法都寫在一個更LINQ的方式,因爲它產生一個可枚舉:

/// <summary> 
/// Provide utilities methods related to <see cref="Control"/> objects 
/// </summary> 
public static class ControlUtilities 
{ 
    /// <summary> 
    /// Find the first ancestor of the selected control in the control tree 
    /// </summary> 
    /// <typeparam name="TControl">Type of the ancestor to look for</typeparam> 
    /// <param name="control">The control to look for its ancestors</param> 
    /// <returns>The first ancestor of the specified type, or null if no ancestor is found.</returns> 
    public static TControl FindAncestor<TControl>(this Control control) where TControl : Control 
    { 
     if (control == null) throw new ArgumentNullException("control"); 

     Control parent = control; 
     do 
     { 
      parent = parent.Parent; 
      var candidate = parent as TControl; 
      if (candidate != null) 
      { 
       return candidate; 
      } 
     } while (parent != null); 
     return null; 
    } 

    /// <summary> 
    /// Finds all descendants of a certain type of the specified control. 
    /// </summary> 
    /// <typeparam name="TControl">The type of descendant controls to look for.</typeparam> 
    /// <param name="parent">The parent control where to look into.</param> 
    /// <returns>All corresponding descendants</returns> 
    public static IEnumerable<TControl> FindDescendants<TControl>(this Control parent) where TControl : Control 
    { 
     if (parent == null) throw new ArgumentNullException("control"); 

     if (parent.HasControls()) 
     { 
      foreach (Control childControl in parent.Controls) 
      { 
       var candidate = childControl as TControl; 
       if (candidate != null) yield return candidate; 

       foreach (var nextLevel in FindDescendants<TControl>(childControl)) 
       { 
        yield return nextLevel; 
       } 
      } 
     } 
    } 
} 

得益於this關鍵字,這些方法擴展的方法和可以簡化代碼。

例如,要查找頁面中所有DropDownList,您只需撥打:

var allDropDowns = this.Page.FindControl<DropDownList>(); 

因爲使用了yield關鍵字的,因爲LINQ的是足夠聰明推遲枚舉的執行,你可以撥打電話(例如):

var allDropDowns = this.Page.FindDescendants<DropDownList>(); 
var firstDropDownWithCustomClass = allDropDowns.First(
    ddl=>ddl.CssClass == "customclass" 
    ); 

枚舉將盡快在First方法謂語滿足停止。整個控制樹不會走。

+1

最全面的答案,它的作品就像一個魅力的歡呼夥計。 – Anicho

+0

http://msdn.microsoft.com/en-us/library/yt340bh4.aspx關於msdn的好文章很好。 – Anicho

+0

我喜歡它。很好,我不再需要使用yield關鍵字,這使得遞歸函數始終運行,即使我聲明Visual Studio跨越它。 – JonathanWolfson

0
 var dropDownLists = new List<DropDownList>(); 
     foreach (var control in this.Controls) 
     { 
      if (control is DropDownList) 
      { 
       dropDownLists.Add((DropDownList)control); 
      } 
     } 
+7

我敢確定你需要緩解。 – SLaks

2

通過頁面上的控件循環不難 - 你只需要在每個控件中查看更多的控件。

你可以做類似

foreach(var control in Page) 
{ 
    if(control is DropDownList) 
    { 
     //Do whatever 
    } 
    else 
    { 
     //Call this function again to search for controls within this control 
    } 
} 
+2

這不起作用。需要遞歸。 –

+2

這就是其他的是... //再次調用這個函數來搜索這個控件中的控件......這就是要求恢復的東西... –

1

您可以使用遞歸的邏輯來獲得所有的控制,就像這樣:

private void PopulateSelectList(Control parentCtrl, List<DropDownList> selectList) 
{ 
    foreach (Control ctrl in parentCtrl.Controls) 
    { 
     if (ctrl is DropDownList) 
     { 
      selectList.Add(((DropDownList)ctrl); 
      continue; 
     } 
     FindAllControls(ctrl, selectList); 
    } 
} 
14
foreach (DropDownList dr in this.Page.Form.Controls.OfType<DropDownList>()) 
{ 

} 
+0

一個代碼的劑量相同的情況下效率更高xD – Anicho

+2

爲了正確工作,它應該是遞歸的。 –

+0

是啊!您需要迭代每個控件Controls集合 - 遞歸。但是,我認爲這些擴展方法非常有用,因爲它們使代碼更加緊湊 - 更少工作的更多工作。 – marko

5

曾有過這個問題,雖然我發現史蒂夫B的回答有用,我想一個擴展方法,所以重新分解它:

public static IEnumerable<T> GetControlList<T>(this ControlCollection controlCollection) where T : Control 
    { 
     foreach (Control control in controlCollection) 
     { 
      if (control is T) 
      { 
       yield return (T)control; 
      } 

      if (control.HasControls()) 
      { 
       foreach (T childControl in control.Controls.GetControlList<T>()) 
       { 
        yield return childControl; 
       } 
      } 
     } 
    } 
+0

我在「this」上顯示「Type expected」時出現智能錯誤。我只是將其添加到app_code文件夾中的類中。 – Fandango68

4

這裏是一個遞歸版本,返回的控制集合請求的類型而不是利用另一個參數:

using System.Collections.Generic; 
using System.Web.UI; 
// ... 
public static List<T> GetControls<T>(ControlCollection Controls) 
where T : Control { 
    List<T> results = new List<T>(); 
    foreach (Control c in Controls) { 
    if (c is T) results.Add((T)c); 
    if (c.HasControls()) results.AddRange(GetControls<T>(c.Controls)); 
    } 
    return results; 
} 

插入到您的類(靜態可選)。

0

如果您使用system.web.ui 中的表單組件,那麼這個方法可行,但是當您從system.web.mvc中顯式使用它們時,這不起作用,所以我想出了以下解決方法。

for (Int32 idx = 0; idx < formCollection.Count; idx += 1) 
        { 
        String Name = formCollection.Keys[idx]; 
        String value = formCollection[idx]; 

        if (Name.Substring(0, 3).ToLower() == "chk") 

         { 
         Response.Write(Name + " is a checkbox <br/>"); 
         } 
        else if (Name.Substring(0, 5).ToLower() == "txtar") 
         { 
         Response.Write(Name + " is a text area <br/>"); 
         } 
        else if (Name.Substring(0, 2).ToLower() == "rd") 
         { 
         Response.Write(Name + " is a RadioButton <br/>"); 
         } 

        } 

這對我的作品,但是我發現,如果沒有選中的單選按鈕是空,因此犯規返回任何這是確定我沒有寫任何東西到數據庫中,如果它是空

相關問題