WinForms 容器控制項 (Form、Panel、GroupBox) 形成控制項樹。本文實作 GetControls<T> 擴展,支援型別篩選、條件過濾、遞迴遍歷,讓批次操作控制項如同 LINQ 查詢般簡潔。
Control → ScrollableControl → ContainerControl → FormControl → ButtonBase → Button, CheckBox, RadioButtonControl → TextBoxBase → TextBox, RichTextBoxControl → ListControl → ListBox, ComboBoxpublic static IEnumerable<T> GetControls<T>(
this Control parent,
Func<T, bool> predicate = null) where T : Control
{
foreach (Control child in parent.Controls)
{
if (child is T typed)
{
if (predicate == null || predicate(typed))
yield return typed;
// 繼續遞迴搜尋子控制項 (容器控制項可能同時符合型別條件)
foreach (var descendant in child.GetControls(predicate))
yield return descendant;
}
else
{
// 非目標型別,仍需遞迴搜尋其子控制項
foreach (var descendant in child.GetControls(predicate))
yield return descendant;
}
}
}
// 輔助:ForEach 擴展
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source) action(item);
}
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
// 1. 禁用所有按鈕
this.GetControls<Button>().ForEach(b => b.Enabled = false);
// 2. 反轉 GroupBox1 內所有 CheckBox 狀態
this.GetControls<CheckBox>(c => c.Parent == groupBox1)
.ForEach(c => c.Checked = !c.Checked);
// 3. 設定特定 Label 顏色
this.GetControls<Label>(l => l.Name == "label1")
.FirstOrDefault()?.ForeColor = Color.Red;
// 4. 取得所有 TextBox 並清空
this.GetControls<TextBox>().ForEach(t => t.Clear());
// 5. 複雜條件:啟用所有可見且可編輯的 TextBox
this.GetControls<TextBox>(t => t.Visible && t.ReadOnly == false)
.ForEach(t => t.BackColor = Color.White);
}
}
// 僅搜尋 Panel 容器內的控制項
public static IEnumerable<T> GetControlsIn<T>(
this Control parent,
Func<T, bool> predicate = null) where T : Control
{
foreach (Control child in parent.Controls)
{
if (child is Panel panel)
{
foreach (var ctrl in panel.GetControls(predicate))
yield return ctrl;
}
}
}
where T : Control 確保型別安全,避免無效轉型。控制項選擇器將「尋找控制項」與「操作控制項」解耦,配合 Lambda 運算式實現聲明式 UI 操作,大幅減少巢狀迴圈與型別檢查代碼,是 WinForms 開發的必備工具方法。