16

I have a custom control with a FlowLayoutPanel embedded within, to which I add elements (other custom controls). In the layout event of the FlowLayoutPanel I resize all of the controls in the FlowLayoutPanel to the size of the containing FlowLayoutPanel.

This goes fine until a vertical scrollbar is needed (AutoScroll = True), taking space inside the FLpanel, causing an horizontal scrollbar to appear.

The gibberish you see is some random placeholder text that I generate in the element's constructor.

I would like to prevent this:

nasty scrollbar effect

I tried adding a vertical scroll control to the usercontrol and doing FlowLayoutPanel.VertScroll.Value=sender.value in the Scroll event: it seems to work, but makes the actual vertical and horizontal scrollbars flicker (appearing and disappearing) a lot when moving the scrollbar control.

I really don't know if there is some property to make the scrollbar external to the FlowLayoutPanel control contents.

I'm doing this in VB.Net, but C# answers are fine (as it is basically the same syntax, at least when working with controls & UI).

Edit


I forgot to mention that I have WrapContents=false and AutoScroll=true in the FlowLayoutPanel.

Also, if you think this design is familiar: it is a pixel-perfect copy of Opera M2's mail list screen.

Update 1


After your comments, I came up with this:

Public Class FlowListPanel ' The user control

Private Sub Me_Load(sender As Object, e As EventArgs) Handles Me.Load
    FL_Panel.AutoScroll = True ' FL_Panel is the FlowLayoutPanel
    FL_Panel.WrapContents = False

    FL_Panel.Dock = System.Windows.Forms.DockStyle.Fill
    FL_Panel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown
    FL_Panel.Margin = New System.Windows.Forms.Padding(0)
End Sub

Sub AddItem(c As Control)
    FL_Panel.Controls.Add(c)
    ReorderControls()
End Sub

Private Sub FLP_CSC(sender As Object, e As EventArgs) Handles FL_Panel.ClientSizeChanged
    ReorderControls()
End Sub

Sub ReorderControls()
    For Each ctrl In FL_Panel.Controls
        ctrl.Width = FL_Panel.ClientSize.Width
    Next
End Sub

Private Sub FL_Panel_L(sender As Object, e As LayoutEventArgs) Handles FL_Panel.Layout
    ReorderControls()
End Sub

End Class

It seems to work, but there is a problem with the horizontal scrollbar showing up when the critical point at which the vertical scrollbar appears is reached.

Once another item is added the horizontal scrollbar vanishes.

Also, I thought that the problem could be caused by the ReorderControls sub not being called, so I made a button to call it, but nothing changed.

This problem is not present when removing elements (but it only occurs when adding).

It also occurs when the window is resized and the vertical scrollbar must appear.

As I show below, after a new element is added it works fine:

nasty scrollbar effect returns

Update 2


I have followed Plutonix's advise (adapting the code from his other answer), and so I have applied some modifications to the ReorderControls sub, in this way:

    Sub ReorderControls()

    Dim HScrollVis As Boolean = NativeMethods.IsHScrollVisible(FL_Panel)

    If HScrollVis Then ' HScroll visible -> kill it with fire!
        NativeMethods.ShowHideScrollBar(FL_Panel,
                                        NativeMethods.SBOrientation.SB_HORZ,
                                        False)
        Return ' as it works anyway...
    End If

    For Each ctrl In FL_Panel.Controls
        ctrl.Width = FL_Panel.ClientSize.Width
    Next
    End Sub

Now the horizontal scrollbar flickers one time, instead of staying there, when the vertical one appears.

I like gifs, so here is the current effect:

nasty scrollbar effect: a new hope

As you probably can't see (due to the low frame rate of the gif), the horizontal bar is probably noticeable only to someone looking for it, for a fraction of second.

I consider the problem 80% solved, and will move on. If I or someone comes up with something definitive, I'll promptly accept the answer.

Community
  • 1
  • 1
beppe9000
  • 1,056
  • 1
  • 13
  • 28
  • 1
    You need to expand your control to have more horizontal space.. Just reduce some of that white space you have between the text and font, you have plenty of space to utilize. Don't make it harder than it needs to be – JeremyK Feb 09 '15 at 19:53
  • have you tried this: http://stackoverflow.com/questions/5556561/how-to-disable-horizontal-scroll-bar-in-flowlayoutpanel ? – Ronaldinho Learn Coding Feb 09 '15 at 19:53
  • have you tried doing this using the windows Messaging / WinProc..? here is an example http://stackoverflow.com/questions/16009743/how-to-stop-flickering-in-c-sharp-windowsforms-form-application – MethodMan Feb 09 '15 at 20:02
  • if you dont want a HScroll, you will need to shrink the width of the things so they and a VScroll fits. If you dont like the gap/BG showing, you can add code to the `ClientSizeChanged` event, and shrink them when it changes (there appears to be only 6 when it pops up). You might also add a few PInvokes to eat the HScroll so it does not pop up then go away when the 7th is added. OTOH, that could perhaps be built into them as custom controls? – Ňɏssa Pøngjǣrdenlarp Feb 09 '15 at 20:09
  • @JeremyK I was thinking about it, but I have no idea on how to get the size of the scrollbar, nor on what event is suitable (now i know, thanks tp Plutonix). – beppe9000 Feb 09 '15 at 20:34
  • @ Plutonix can you elaborate a bit on the custom control? I have tried using a VScrollbar Scroll event, but the original scrollbars flickered on update, so I discarded that approach. – beppe9000 Feb 09 '15 at 20:34
  • BTW, I am going thru the route of resizing. – beppe9000 Feb 09 '15 at 20:35
  • [this answer](http://stackoverflow.com/a/24722635/1070452) should have all the stuff you need; just change it to shrink your widgets instead of LV Items. It will also put the pixels back if/when the VScroll disappears. The thing of the VScroll appearing for a sec was exactly what I was talking about - use the PInvokes to eat the HScroll when it appears (that code is there too). Its actually a fair amount of code to do so little, but if you cant live with it... – Ňɏssa Pøngjǣrdenlarp Feb 09 '15 at 22:17
  • I'll check it out... – beppe9000 Feb 09 '15 at 22:31
  • I mean just expand your form a bit more so it will fit without needing a horizontal scroll bar – JeremyK Feb 10 '15 at 00:26
  • @plutonix I updated the question with some code I integrated from your other answer (which I up'd :P). – beppe9000 Feb 10 '15 at 09:56
  • As the link explains, Windows will still call for the HScroll and that happens before you resize the child controls. The event is then called a second time as a result at which point your code removes it, ASAP. Your code looks like you are doing that as well/fast as it can; perhaps adding Suspend/ResumeLayout might help. Even looking for it, I have never been able to see it, even though I know it must be there. The only way to remove it even faster is to override WndProc and eat it there. – Ňɏssa Pøngjǣrdenlarp Feb 10 '15 at 12:55
  • I had tried a Suspend/Resume Layout, but it yielded an awkward result when resizig the window (it slowed the resizing, also). So, basically I'm done (if I want to leave it simple enough). – beppe9000 Feb 10 '15 at 15:50

2 Answers2

2

Here is an alternative approach that gives you your desired result. Granted it does NOT directly answer your question, but in my opinion, if you need to mess with the way controls work in order to get your desired solution, you are not using the correct controls.

Instead of adding your controls directly into a FowLayoutPanel,

Use a standard Panel object containing a TableLayoutPanel.

Set the Panel Properties to...

AutoScroll=True

Set the TableLayoutPanel properties to

Dock = Top

Autosize = True , GrowAndSHrink

Start out with just one cell in the TableLayoutPanel..

Now add your controls to the TableLayoutPanel...

e.g.

Dim CTRL As New Your_User_Control
TableLayoutPanel1.Controls.Add(CTRL)
CTRL.Dock = DockStyle.Top

When the scrollbar appears the TableLAyoutPanel will shrink horizontally by the appropriate amount, and all the contained controls will also shrink automatically.

LarsTech
  • 80,625
  • 14
  • 153
  • 225
Trevor_G
  • 1,331
  • 1
  • 8
  • 17
0

Just make sure you initialize it with these properties:

this.WrapContents = false;
this.AutoScroll = true;

You'll also need to ensure the controls you're adding to it have a maximum width of the control width minus the scrollbar width.

That should do it though.


Edit:

I got this solution out of one of my custom controls. It appears to be very similar to this post however - I may have got it from there initially, I can't really remember. Post linked just in case.


Edit 2:

As you're already setting those properties, and looking at the image, you simply need to make the controls you're adding to the FlowPanel narrower, or the FlowPanel wider.

Basically, you have to just allow for the space the scrollbar will take up when it appears. You could detect if it's visible and force the inner controls to update their layout accordingly if you really want to use all the width at all times.

Community
  • 1
  • 1
Octopoid
  • 3,507
  • 5
  • 22
  • 43
  • I updated the question, as I was already using those settings, but i forgot to specify it in the question. ;) – beppe9000 Feb 09 '15 at 20:36
  • Have you tried adding `this.Invalidate();` to the `ClientSizeChanged` handler? I suspect you just need to tell the control to redraw itself again, as you're only changing the size of the contents after it's performed it's layout change. – Octopoid Feb 09 '15 at 22:47
  • I tried Invalidate on both the user control and the flowlayoutpanel, with no results. However, I kinda solved predating on @plutonix suggestion. Now all i got is a rapid flicker when the vbar appears. Which is acceptable for me, as it is almost unnoticeable... – beppe9000 Feb 09 '15 at 23:07
  • Excellent - I might have a try at fixing it without, as I suspect it was very nearly there - the fact it disappears after you add ANOTHER item leads me to believe you just need to change the order around a bit or flag a redraw or layout update at the right moment. If I get it working I'll update the answer. – Octopoid Feb 09 '15 at 23:12
  • Yeah, I've got the same feeling. :) – beppe9000 Feb 09 '15 at 23:27