入れ子になった配下のコントロールをすべて列挙するをさらに改良して使いやすくしました。
- 列挙するコントロールの型を指定
- 列挙後のキャストが不要になる上に、不要なコントロールを列挙しないことによる高速化が期待できます。
- 抽出条件を指定できるようにする
- 列挙後にさらに条件を追加して対象コントロールを絞り込むことも多いだろうから、列挙メソッド側の機能として持った方がいいかなと。
IEnumerable<T> GetAllControls<T>(Control ctrl, Func<T, bool> predicate = null)
where T : Control
{
if (predicate == null) predicate = _ => true;
IEnumerable<T> list = ctrl.Controls.OfType<T>().Where(predicate);
return list.Concat(ctrl.Controls.Cast<Control>().SelectMany(child => GetAllControls<T>(child, predicate)));
}
使い方
//名前が"ID"で終わるテキストボックスをdisableに
foreach(var txtbox in GetAllControls<TextBox>(form, c => c.Name.EndsWith("ID")))
{
txtbox.Enabled = false;
}
//名前が"panel"で始まるコンテナ直下のテキストボックスを非表示に
foreach(var txtbox in GetAllControls<TextBox>(form, c => c.Parent?.Name.StartWith("panel") ?? false))
{
txtbox.Visible = false;
}
WPF版(論理ツリー)
IEnumerable<T> GetAllControls_WPF<T>(FrameworkElement element, Func<T, bool> predicate = null)
where T : FrameworkElement
{
if (predicate == null) predicate = _ => true;
var childrenList = LogicalTreeHelper.GetChildren(element).OfType(FrameworkElement);
IEnumerable<T> list = childrenList.OfType(T).Where(predicate);
return list.Concat(childrenList.SelectMany(child => GetAllControls_WPF<T>(child, predicate)));
}
最近WPFいじってないのでビジュアルツリーでの列挙とか使い方はなし
修正(6/19)
predicateを省略した場合の対応が抜けていたので修正しました。