Q:

Is it possible to find which userControl are visible in a flowlayoutPanel

I have a FlowLayoutPanel that I add 50 UserControl to dynamically. The panel  is positioned vertically and each user control has some labels that are read-only.
I use this.KeyPreview = true;
in the form so I can use the event handler Form1_KeyUp to catch keyUp event.
In this event handler, I catch the navigation buttons ↑, ↓, →, ←, PageUp and PageDown.
When I click the navigation button ↑ the previous UserControl is selected in the panel and when click ↓ the next UserControl is selected. This works good.
The customer want also to be able to use PageUp and PageDown which I catch in the event handler Form1_KeyUp as I mentioned before.
I hope that I can find which UserControl that are visible. Assume UserControl with index 1,2,3,4 are visible in the panel then I can select user control at index 1 when I use PageUp and user control at index 4 when I click PageDown.
Any help is welcome.

A:

You can use such code:
var controls = container.Controls.Cast<Control>().OrderBy(x => x.Top);
var visibles = controls.Where(l => container.ClientRectangle.IntersectsWith(l.Bounds));
var top = visibles.FirstOrDefault();
var bottom = visibles.LastOrDefault();

In above code, I first ordered controls of container by Top of them. Then using IntersectsWith I found those controls that their bounds has intersection with client rectangle of container which means those controls are visible.
Since the list is ordered by Top property of controls, the first item is the visible one at top of container and the last item is the visible one at bottom of container.
Note

Instead of Cast<Control> you can use OfType<YourUserControl>.
Instead of OrderBy(x => x.Top) you can use OrderByDescending(x => container.Controls.IndexOf(x))
You can bring the top control into view using container.ScrollControlIntoView(top); or the bottom control container.ScrollControlIntoView(bottom);
If you have a FlowLayoutPanel with AutoScroll=True and FlowDirection=TopDown and WrapContents=False then you can use a Panel instead, just when adding user controls, set Dock=Top for them.

