FlowLayoutPanel for .NET Compact Framework

It is quite complex to arrange Windows Form layout dynamically in .NET Compact Framework (CF) when you try to show/hide a control between other controls. Although you can use FlowLayoutPanel in desktop Windows Form application, there is no such kind of layout manager for CF.

I found an old article on CodeProject about FlowLayoutPanel, but that code cannot work on CF because CF Panel does not have OnLayout event. Also the code logic has bugs too.

After searching for a while, I decided to make a FlowLayoutPanel for CF by myself. It turns out the code is not hard to write:

Protected Overloads Overrides Sub OnPaint(ByVal pEvent As PaintEventArgs)
 Dim nextTop As Integer = 0, nextLeft As Integer = 0
 Dim maxHeight As Integer = 0
 Dim ParentWidth As Integer
 
 If Me.Parent IsNot Nothing Then
  ParentWidth = Me.Parent.Width
 Else
  ParentWidth = Me.Width
 End If

 ' Modify control location for the layout
 For Each myControl As Control In Me.Controls
  ' Ignore invisible controls
  If myControl.Visible = False Then
   Continue For
  End If

  If (nextLeft + myControl.Width) > ParentWidth Then
   nextTop += maxHeight
   nextLeft = 0
   ' Reset maxHeight
   maxHeight = 0
  End If

  myControl.Top = nextTop
  myControl.Left = nextLeft

  If myControl.Height > maxHeight Then
   maxHeight = myControl.Height
  End If

  nextLeft += myControl.Width
 Next
 Me.AutoScrollPosition = New System.Drawing.Point(0, 0)

 MyBase.OnPaint(pEvent)
End Sub

Below is a sample using the logic above:


To make layout easier, I put several panels inside the FlowLayoutPanel. You can see all the controls are arranged properly. When I click the "Hide Panel 3" button, the Form becomes this:


The controls below Panel 3 are moved up automatically. If I click "Show Panel 3" button, the Panel 3 will be displayed at original place and all the controls below it are moved down accordingly.

The code for the button is like below:

Private Sub btnHide_Click(ByVal sender As Object, ByVal e As EventArgs)
 If btnHide.Text = "Hide Panel 3" Then
  Panel3.Visible = False
  btnHide.Text = "Show Panel 3"
 Else
  Panel3.Visible = True
  btnHide.Text = "Hide Panel 3"
 End If

 ' Refresh the flow layout panel
 Me.FlowLayoutPanel1.Invalidate()
End Sub

There is a small problem in Visual Studio though: when you drag-drop a control to the FlowLayoutPanel, Visual Studio always puts the control as the first one inside the FlowLayoutPanel. You need to modify the designer file to manually put those controls in order:

'FlowLayoutPanel1
'
Me.FlowLayoutPanel1.Controls.Add(Me.Panel1)
Me.FlowLayoutPanel1.Controls.Add(Me.Panel2)
Me.FlowLayoutPanel1.Controls.Add(Me.Panel3)
Me.FlowLayoutPanel1.Controls.Add(Me.Panel5)
Me.FlowLayoutPanel1.Controls.Add(Me.Panel6)
Me.FlowLayoutPanel1.Controls.Add(Me.Panel4)

2 comments:

Anonymous said...

Very nice idea to get a flowlayout. I was looking for soemthing like javas awt flow control and stumbled into your post.

Many thanks for sharing this.

see my website hjgode.de/wp

josef

Sypher_04 said...

I just stumbled across this now, like 5 months after posting, so I have no idea if this will reach you or not, but I wanted to say thanks for this code. Helped me a lot.

Also, wanted to leave you a tip to make this better, easier to use. If you enumerate through the Controls array, in reverse order it will eliminate the drag issue where the control always goes to the top.

Take Care.
Kevin