You can make things more concise with LINQ. Here's one way that should work:
List<Control> getControls(Control container, Rectangle rect, bool bContained = false)
{
rect = RectangleToClient(rect);
return (from Control ctl in container.Controls
where rect.IntersectsWith(ctl.Bounds) == bContained
let ctls = new List<Control> { ctl }.Union(ctl.Controls.OfType<Control>())
select ctls).SelectMany(x => x).ToList();
}
This basically does the same thing, filters the collection according to bContained
. Creates a collection of lists that each contain the parent control and its sub-controls. Then flattens them into one list.