1

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.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
tony
  • 127
  • 1
  • 1
  • 7

3 Answers3

2

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.
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • Yes I use your suggested code and I had to add additional code do navigate up or down in the flowlayoutpanel depending of the height of the form. – tony Sep 16 '16 at 06:00
  • @tony I believe you don't need to use height of form and instead you can use such code `container.ScrollControlIntoView(someControl); ` to bring `someControl` into view. Here `container` is your `FlowLayoutPanel`. – Reza Aghaei Sep 16 '16 at 06:52
  • By the way, if the flow which you need is just vertical and your `FlowLayoutPanel` has scrollbars, then I believe you can easily use a `Panel` instead and then when adding your user controls, `Dock` them to `Top`. See an example [here](http://stackoverflow.com/a/32887572/3110834). – Reza Aghaei Sep 16 '16 at 06:56
  • Also using a `FlowLayouPanel` with `AutoScroll=True` and `FlowDirection=TopDown` and `WrapContents=False` I could bring the control into view using `container.ScrollControlIntoView(someControl);`. – Reza Aghaei Sep 16 '16 at 07:14
0

if I understand you correctly , this is what you meant

 public List<Control> GetvisibleControls(Control parent)
            {
                List<Control> returnList = new List<Control>();
                foreach(Control child in parent.Controls)
                {
                    if (child.Location.X < parent.Width && child.Location.Y < parent.Height)
                        returnList.Add(child);
                }
                return returnList;
            }
Pepernoot
  • 3,409
  • 3
  • 21
  • 46
0

If by visible you mean, Visible property is true, use 'Shannon Holsinger' answer:

If you mean at least one pixel of a control can be seen, loop on all controls, and use this answer for checking if the control is visible

C# winform check if control is physicaly visible

Community
  • 1
  • 1
Zag Gol
  • 1,038
  • 1
  • 18
  • 43