Kiểm tra my previous SO answer.
Về cơ bản, ý tưởng là để bọc các đệ quy của iterating thông qua các bộ sưu tập điều khiển sử dụng:
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);
}
}
và sử dụng nó:
List<DropDownList> allControls = new List<DropDownList>();
GetControlList<DropDownList>(Page.Controls, allControls)
foreach (var childControl in allControls)
{
// call for all controls of the page
}
[Sửa 2013/11/26] : đây là một cách thanh lịch hơn để đạt được mục tiêu này. Tôi đã viết hai phương pháp mở rộng có thể đi bộ cây điều khiển theo cả hai hướng. Các phương pháp được viết bằng một LINQ cách hơn vì nó tạo ra một đếm được:
/// <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;
}
}
}
}
}
Nhờ có từ khóa this
, những phương pháp này mở rộng phương pháp và có thể đơn giản hóa mã.
Ví dụ, để tìm tất cả DropDownList
trong trang, bạn chỉ có thể gọi:
var allDropDowns = this.Page.FindControl<DropDownList>();
Bởi vì việc sử dụng các từ khóa yield
, và vì LINQ là đủ thông minh để trì hoãn việc thực hiện các kiểu liệt kê, bạn có thể gọi (ví dụ):
var allDropDowns = this.Page.FindDescendants<DropDownList>();
var firstDropDownWithCustomClass = allDropDowns.First(
ddl=>ddl.CssClass == "customclass"
);
Việc liệt kê sẽ dừng lại ngay khi có biến vị ngữ trong phương pháp First
. Toàn bộ cây điều khiển sẽ không được đi.
Câu trả lời toàn diện nhất và nó hoạt động như một sự cổ vũ. – Anicho
http://msdn.microsoft.com/en-us/library/yt340bh4.aspx Bài viết hay về msdn là tốt. – Anicho
Tôi thích nó. Thật tốt là tôi không còn cần phải sử dụng một từ khóa lợi nhuận, mà làm cho nó để chức năng đệ quy luôn luôn chạy mặc dù tôi tuyên bố Visual Studio để bước qua nó. – JonathanWolfson