Question Save control locations in FlowlayoutPanel

daveofgv

Well-known member
Joined
Sep 17, 2008
Messages
218
Location
Dallas, TX
Programming Experience
1-3
Hi Everyone!

I have a flowlayoutpanel and the controls inside can be dragged and dropped. They are panels with textbox and label on each panel (roughly 40 panels or so) The problem is that when the user closes the form (or application) I need the controls to remain in the same position as they moved them. I have a My.Settings named My.Settings.controllocations and have it set to System.Collection.Specialized.StringConnection (which works for the controls on the form, but not for the controls inside the flowlayoutpanel.

Here is my code right now (which I found some of the code on this site a long time ago - but not sure where - I believe maybe from JohnH, idk):

VB.NET:
Private Sub Form4_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        For Each child As Control In Me.FlowLayoutPanel1.Controls
            AddHandler child.MouseDown, AddressOf childs_MouseDown
        Next
        For Each child As Control In Me.FlowLayoutPanel1.Controls
            For Each item In My.Settings.controlLocations
                If Split(item, "!")(0) = child.Name Then
                    child.Location = New Point(Split(item, "!")(1), _
      Split(item, "!")(2))
                End If
            Next
        Next

VB.NET:
Private dragcursor As Cursor, dragtype As Type

    Private Sub childs_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs)
        If Me.ReorderCheckBox.Checked Then
            Dim source As Control = CType(sender, Control)
            Using bmp As New Bitmap(source.Width, source.Height)
                source.DrawToBitmap(bmp, New Rectangle(Point.Empty, source.Size))
                Me.dragcursor = New Cursor(bmp.GetHicon)
            End Using
            Me.dragtype = source.GetType
            Me.FlowLayoutPanel1.DoDragDrop(source, DragDropEffects.Move)
            Me.dragcursor.Dispose()
        End If
    End Sub

VB.NET:
Private Sub FlowLayoutPanel1_GiveFeedback(ByVal sender As Object, ByVal e As System.Windows.Forms.GiveFeedbackEventArgs) Handles FlowLayoutPanel1.GiveFeedback
        e.UseDefaultCursors = False
        Cursor.Current = Me.dragcursor
    End Sub

VB.NET:
Private Sub FlowLayoutPanel1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles FlowLayoutPanel1.DragEnter
        If e.AllowedEffect = DragDropEffects.Move AndAlso e.Data.GetDataPresent(dragtype) Then
            e.Effect = DragDropEffects.Move
            Me.Refresh()

        End If
    End Sub

VB.NET:
Private Sub FlowLayoutPanel1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles FlowLayoutPanel1.DragDrop



        Dim source As Control = CType(e.Data.GetData(dragtype), Control)
        Dim target As Control = Me.FlowLayoutPanel1.GetChildAtPoint(Me.FlowLayoutPanel1.PointToClient(New Point(e.X, e.Y)))
        If target IsNot Nothing Then
            Dim ix As Integer = Me.FlowLayoutPanel1.Controls.GetChildIndex(target)
            Me.FlowLayoutPanel1.Controls.SetChildIndex(source, ix)
            My.Settings.controlLocations.Clear()
            For Each Control As Control In Me.FlowLayoutPanel1.Controls
                My.Settings.controlLocations.Add(Control.Name & "!" _
      & Control.Location.X & "!" & Control.Location.Y)
            Next
            My.Settings.Save()
        End If
    End Sub

VB.NET:
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        My.Settings.controlLocations.Clear()
        For Each Control As Control In Me.FlowLayoutPanel1.Controls
            My.Settings.controlLocations.Add(Control.Name & "!" _
  & Control.Location.X & "!" & Control.Location.Y)
        Next
        My.Settings.Save()
    End Sub
End Class

I do not receive any errors, however, the controls are not saved in the location that were last moved.

Any help would be much appreciated!

Thanks in advanced

daveofgv
 
Controls in FlowLayoutPanel are not layed out by Location, they just flow in order of their index, so you just store their index and set this when restoring order, using GetChildIndex/SetChildIndex methods.
 
Thanks for the Reply. Trying to figure this out - it appears I cannot use the System.Collections.SpecializedStrings.Collection settings? It appears, so far, that I have to use SetChildIndex / GetChildIndex for every control in my flowlayoutpanel? The reason why I ask - is that I will have about 60 or so panels in the flowlayoutpanel. I was hoping that when a user (at runtime) drags and drops the panels where they want them - then they will be able to click a button and the positions save.

Thanks in advanced.
 
Last edited:
Hi,

I think you have misunderstood what JohnH has tried to tell you. If you want to save some control information with each controls relative position within a FlowLayoutPanel (FLP) then you need to use the GetChildIndex Method of the FLP and save that index along with your control information so that you can Restore the controls Relative Index in the FLP with the SetChildIndex Method of the FLP when you read the control information back into your project. How you do that is up to you but as an example have a look at this:-

Save some control information with its relative index within an FLP:-
For Each someControl As Control In FlowLayoutPanel1.Controls
  My.Settings.someCollection.Add(String.Format("{0}|{1}", someControl.Text, FlowLayoutPanel1.Controls.GetChildIndex(someControl).ToString))
Next


In this case I concatenate some control information to its relative position within the FLP and then save that information in a StringCollection. Note that this information id delimited by the ?|? character.

To read that information back:-
For Each stringValue As String In My.Settings.someCollection
  Dim stringElements As String() = stringValue.Split("|"c)
  Dim myControl As New TextBox With {.Text = stringElements(0)}
 
  FlowLayoutPanel1.Controls.Add(myControl)
  FlowLayoutPanel1.Controls.SetChildIndex(myControl, CInt(stringElements(1)))
Next


Notice that after getting each Value from the StringCollection, the value is split between the control information and its relative index in the FLP. The control is then created, added to the FLP and finally its relative position within the FLP is set with the SetChildINdex Method.

Hope that helps.

Cheers,

Ian
 
Hi Ian -

Thank you for the clarification reply. I do have a question though....

In your code:

VB.NET:
 Dim myControl As New TextBox With {.Text = stringElements(0)}

it looks like it is referencing a textbox. If I have around 50-60 panels (with a textbox and label on each panel) in the same FLP will I have to reference all of them like the textbox is declared?

Also, when I use the code to read back the information - it actually doubles what I have originally instead of reading back what the locations were.

Sorry for the misunderstanding :apologetic:

Thanks in advanced.
 
Back
Top