Home » VB.Net

Sorting a bunch of Controls in a FlowLayoutPanel - Having Problems

Good day to all,

apart from it being my birthday, found some quick time to post this question on here.


I have a flowlayoutpanel, and a bunch of controls inside it.

I would like to actually SORT the controls, depending on some values.


For Example:
The FlowLayoutPanel has 4 Controls:

Each control has: Name (string), Maker (string) and Rated (integer) values.

So what I thought of was:


 s AsNew
ForEach c As MyOwnControl In FlowLayoutPanel1.Controls
s.Add(c.title.Text, c)
ForEach c As CustomControl In s.Values


That would arrange the controls depending on the title.text each one has. Now this works but its not very optimal and it will dont work for DESCENDING or work properly with the Rated integer.


Now I had a search around forums and came across Icomparable, and decided to have a go at it but I can't really get it to work:


Implements IComparable
Private m_title AsString
Private m_maker AsString
Private m_rated AsInteger

PublicSubNew (ByVal thetitle AsString , ByVal themaker AsString , ByVal therated AsInteger )
m_title = thetitle
m_maker = themaker
m_rated = therated
PublicFunction CompareTo(ByVal AnEmployee AsObject ) AsIntegerImplements IComparable.CompareTo

IfCType (AnEmployee, Employee).Rated < Me .Rated Then
Return -1
ElseIfCType (AnEmployee, Employee).Rated = Me .Rated Then
Return 0
ElseIfCType (AnEmployee, Employee).Rated > Me .Rated Then
Return 1

PublicReadOnlyProperty title() AsString
Return m_title
PublicReadOnlyProperty Maker() AsString
ReturnMyClass .m_maker
PublicReadOnlyProperty Rated() AsInteger
ReturnMyClass .m_rated


' AND TO CALL IT is where I came across where I can't go on...:

Dim A AsNew List(Of String )
Dim theEmployees() As Employee
ForEach c As MyOwnControl In FlowLayoutPanel1.Controls
Dim x AsNew Employee(c.title.Text, c.maker.Text, c.rating.text)
'didnt know how to add A to theEmployees (most of the code was grabbed from Microsoft's forums, and didn't fully understand it.

Array.Sort(theEmployees) 'call the CompareTo
Dim aEmployee As Employee
ForEach aEmployee In theEmployees


So as you can see I basiclly messed everything up..

All I wanted was a A..Z (Ascending) sorting option for either the Title, Maker or Rated, and a Z...A (Descending) sorting for the same.

If anyone can put me on the right track it would be great :) Thanks!


6 Answers Found


Answer 1

I've implemented custom IComparable exactly twice myself, and I don't recommend it. It's a painfully long way around in code.

The stock FlowLayoutPanel is a strange animal.  The order in which control items contained in it are sorted (meaning the order they're presented in the flow direction) in the control is totally dependent on the Z-order, or the order in which they were added to the control collection.  There is no direct Z-order accessor, but you can use the BringToFront and SendToBack methods on each individual control; BringToFront immediately plants the control at the FRONT of the display and SendToBack immediately plants it at the END.

There are a couple of ways to make this work to your advantage.

First, you already seem to have an array of custom controls that would be added to it (demonstrated in your first codeblock). What's handy about this is that you can iterate through that array to retrieve JUST the Name, JUST the Maker, or JUST the Rated values. You load those values into an array of the appropriate type (string or integer) and then you just call System.Array.Sort(MyArray) - it sorts from A(a)-Z(z) and sorts numerics starting at 0 and climbing. Why this ascending-only sort is handy for you is because there's also a System.Array.Reverse(MyArray) which instantly turns your neatly ascending sort into a perfect descending sort.

At this point you can iterate back through your original array of controls; match the sorted array value against the appropriate value in each control, and when you hit a match you just call SendToBack or BringToFront on that control and move on to the next one. The thing to watch out for is that you ONLY send it to the back or the front once - if the FIRST element you call should be the FIRST in the display, you need to use SendToBack (which places it at the end of the display) and then it moves up to the front as the other controls are called; if you use BringToFront then the first element you move ends up at the end of the display (which is also handy if you have a clear understanding of what's going on, since you can SKIP the whole array reversal after it's sorted once if you know what you're doing with Z-order manipulation).


Answer 2

Thanks for your reply Andrew,

After reading your post thourougly, I found it quite usefull and had a play around my code.

So speaking about the Array part you were talking about, as I am not very good with them at the moment, I had a go at it but no luck.

It came down to the fact in

Dim myarray as array

I couldn't seem to find a way to actually add "values" to the array. I was trying stuff like:

For Each c As MyOwnControl In FlowLayoutPanel1.Controls
            myarray.Add(c.rated.text, c)


But that doesnt work with Arrays, only with ArrayLists, but then with an array list I can't basiccly have 2 values in the List (one for the rated, and one for the control)


I am not sure what to do as arraylists dont seem to allow multiple values, therefore i wouldn't know which control is the highest one...

Btw, Just reposting the code above as for some reason its all spaced out for some reason:

 Dim s As New SortedList
    For Each c As MyOwnControl In FlowLayoutPanel1.Controls
      s.Add(c.rated.text, c)
    For Each c As MyOwnControl In s.Values

Thanks again for your time, and for helping me!


Answer 3

Dim IntArray(-1) As System.Int32
Dim StringArray(-1) As System.String

This creates 2 arrays; one for Integers and one for Strings.  If you're only sorting by 1 property at a time, this works fine no matter how many properties are Strings or how many are Integers.

'Using this For signature allows you to iterate by index'rather than by object - provides more control.'I can't actually remember the last time I went by object,'but I'm pretty positive that at some point I had to go back to'rewrite the code to go by indexFor c_idx As System.Int32 = 0 to ubound(FlowLayoutPanel1.Controls)
      'This is my 'best practice' recommendation'It allows you to have multiple control types in 'your FlowLayoutPanel, and only muck around with'the specific type that is yours.Dim ThisControl As System.Windows.Forms.Control = FlowLayoutPanel1.Controls(c_idx)
      IfTypeOf ThisControl Is MyOwnControl ThenRedimPreserve IntArray(c_idx)
         IntArray(c_idx) = CType(ThisControl,MyOwnControl).rated
         'I'm assuming here that rated is actually an Integer value'If Rated is instead a nested object with a Text Property'(as your last code post suggests) then you can use'the StringArray instead of the IntArray.EndIfNext c_idx
If there's absolutely nothing but MyOwnControl types in the FlowLayoutPanel.ControlCollection, then this will always produce an array of Rated values that is exactly the same size (and before you call System.Array.Sort(IntArray) on it, exactly the same order) as the ControlCollection itself.


Answer 4

Thanks for helping, ive learnt a lot of your code there.


Error    1    Value of type 'System.Windows.Forms.Control.ControlCollection' cannot be converted to 'System.Array'.

Thats the only problem i had, was the Ubound. So I changed it to For c_idx As System.Int32 = 0 To FlowLayoutPanel1.Controls.Count


And how would I continue by making that sorted array into controls?


Answer 5

I'm not providing any more code, sorry.

But as I outlined in previous posts, your next step is to take your known value and iterate back through the already existing controls to match the sorted known values against the contents of those existing controls.


Answer 6

Oh well, seems Ill have to forget sorting them as I have no clue thats why I asked :/


Thanks anyway for your help



I have two UserControls.  UserControl1 contains a FlowLayoutPanel with a RightToLeft style, and I add UserControl2 to UserControl1.  UserControl2 contains SplitContainers.

When I add a UserControl2 to UserControl1, UserControl2 remains the same size as it is in the designer regardless of what I do.

I have tried setting UserControl2.Dock to DockStyle.Right before I add it to the FlowLayoutPanel.  I have tried various combinations of AutoSize options on these two controls.

I feel I have something setup incorrectly in UserControl2 because if I add this control to a normal form control, it still exhibits the same issue.  The UserControl itself will properly dock, but the SplitContainers within the UserControl don't grow accordingly.

Is there a "gothca" with SplitContainers that I'm not picking up on?


I am using a flow layout panel for several controls that may or may not be visible at run time depending on user preferences.

Most of the controls are label->textbox and I want to know if there is a way to associate,bind,link or whatever the label to the textbox or other control so that I don't end up with a label at the end of one row & then it's associated textbox (or other control) at the beginning of the next line.

I can't use flow break because almost all the controls can be indivdually hidden or visible which makes predicting the breakpoints impossible (or at least impractical)



Is this possible? Let me elaborate.

I need to automate the execution of a bunch of sql script files (*.sql) placed by my users in a certain folder. One way I can do this is by using some kind of a script to loop thru the files in that folder and for each *.sql file found, launch a 'sqlcmd' command to execute the current script file using the -i option, ie,

sqlcmd -S <server> -i <the current sql file in the loop>

I tried doing this, but ran into a liitle bit of difficulty with the particular scripting language (JAVA). I was going to research this a bit more, but I also wanted to consider something that doesn't involve another script.

So I was thinking about doing this using a stored procedure, but then I was wondering, how would I run a sql script file from sql server? The only way I can think of is still using sqlcmd, but then to use that within a stored procedure, I would need to turn on xp_cmdshell.

Although I can do that, that invloves getting other people involved so I was wondering if there is way to do this without turning on xp_cmdshell.



If I want to update 1000 records at a time in the database what is the best approach.

Guide me Pls.


Currently I'm working on a stock chart component (actually porting one from C++ & GDI to WPF) and found a problem when I have to display lots of candles,. Talking about >4000 candles. Every candle is created from a vertical line and a rectangle with gradient, so number of objects actually doubles. I'm using regular Line and Rectangle objects from WPF. It works VERY slow.

I tried to google a bit about WPF rendering performance and found that I may have to use Geometry objects, this may speed up, so I have such a small test
privateconstint count = 4200; 
private Random _r = new Random(); 
privatevoid button1_Click(object sender, RoutedEventArgs e) 
      GeometryGroup figures = new GeometryGroup(); 
for(int i = 0; i < count; i++) 
        Rect r = new Rect(); 
        r.Width = _r.Next((int)ActualWidth); 
        r.Height = _r.Next((int)ActualHeight); 
        r.X = _r.Next((int)(ActualWidth - r.Width)); 
        r.Y = _r.Next((int)(ActualHeight - Height)); 
switch (_r.Next(0, 2)) 
case 0: figures.Children.Add(new EllipseGeometry(r)); 
case 1: figures.Children.Add(new RectangleGeometry(r)); 
      System.Windows.Media.GeometryDrawing geometryDrawing = new System.Windows.Media.GeometryDrawing(); 
      geometryDrawing.Geometry = figures; 
      geometryDrawing.Pen = new Pen(Brushes.Black, 10); 
      DrawingImage drawingImage = new DrawingImage(geometryDrawing); 
      Image anImage = new Image(); 
      anImage.Source = drawingImage; 
      anImage.Stretch = Stretch.None; 
      anImage.HorizontalAlignment = HorizontalAlignment.Left; 
      anImage.Height = ActualHeight; 
      anImage.Width = ActualWidth; 

After pressing the button I have to wait about 3-6 secs to see the result. That's very bad. And I have a pretty powerful PC.
So, how to work with a lot of objects in WPF?



Ok so I have some buttons that you can add picture boxes and buttons and textboxs to the flowpanel while in the program, But i was wondering if there is any way to save it, So like i have.

Dim pic as new picturebox

stuff defining it

Then of course when the user clicks add picture box It adds a new picture control to the flowpanel

then when the user closes the form how could i save the users work? Like if he added like 10 picture boxes with pictures and wrote in the text boxes ect.....on the flowpanel to keep it organized

I need  any way to save the flowpanel with all the things in side of it ect.... Thanks help is much needed and appreciated! :)


Hi ...

Am trying to use sorting and paging using a Asp.net DataList Control.....I found a Tutorial at asp.net website, but not able to understand that ...

I found other two links ,which exactly is of my need...but the only thing is that , it is in VB....



But Am working with C#....Kindly Help me with the Simplest Logic....I wanna Use Sorting & Paging For this Code...

        <table border="2">
        <tr bgcolor="#cc9900">
        <td> <b> Employee's Name </b> </td>
        <td> <b> Employee's Age </b> </td>
        <td> <b> Employee's Joining Date </b> </td>
        <td> <b> Employee's Salary </b> </td>
        <td> <b> Employee's Residence </b> </td>
    <td><%# DataBinder.Eval(Container.DataItem, "EmployeeName")%> </td>
    <td><%# DataBinder.Eval(Container.DataItem, "EmpAge")%> </td>
    <td><%# DataBinder.Eval(Container.DataItem, "DateofJoining")%> </td>
    <td><%# DataBinder.Eval(Container.DataItem, "Salary")%> </td>
    <td><%# DataBinder.Eval(Container.DataItem, "EmpPlace")%> </td>
    <td><asp:LinkButton ID="lnkSelect" runat="server" ForeColor = "Green"
         CommandName="Select" > Select </asp:LinkButton></td>


Am a Beginner ...Kindly Help Me....


My model is as follows:


using System;
using System.Collections.Generic;
using Microsoft.Modeling;

namespace SpecExplorer3.Model
    public static class Program
            public static List<string> names = new List<string>();
            public static void AddName(string name)
            public static void SortName()


and my cord file is:

using SpecExplorer3.Implementation;

config Main
    action abstract static void Accumulator.AddName(string name);   
    action abstract static void Accumulator.SortName();

    switch StepBound = 128;
    switch PathDepthBound = 128;
    switch TestClassBase = "vs";
    switch GeneratedTestPath = "..\\TestSuite";
    switch GeneratedTestNamespace = "SpecExplorer3.TestSuite";
    switch TestEnabled = false;
    switch ForExploration = false;

config ParameterCombination: Main
    action static void Accumulator.AddName(string name)
        where {.
            Combination.In(name, "y", "a", "m");           

machine AccumulatorModelProgram() : Main where ForExploration = true
    construct model program from ParameterCombination
    where namespace = "SpecExplorer3.Model.Program"

machine scenario() : Main where ForExploration = true
(AddName("y"); AddName("a"); AddName("m"); SortName) || AccumulatorModelProgram

machine AccumulatorTestSuite() : Main where ForExploration = true, TestEnabled = true
    construct test cases where strategy = "ShortTests" for scenario()


My problem is, when I explorer scenario machine, the final state does not give me the sorted names list. Please help.


We have a query that runs on SQL 2000 and then we migrate it to SQL 2008.. We used the same query but the results were unproperly sorted. Is there any difference between SQL Server 2000 and 2008 in terms of sorting?


Hello everyone,

I use a dsn connection that loads data into an excel sheet from a sql server db,

the rest of the data (3 additional columns)in this sheet is filled by users.

The data I get from the dsn connection is a customer id and his details, the users of this sheet then fill the rest of the columns with additional data for this customer, let's say their birthdate and address and a calculated field that does not uses data from the dsn columns.

Whenever a user applies any kind of sort in one of the columns and then refresh the data to get new rows from the dsn connection the data from the connection and the data from the additional columns get's mixed up.


Is there a way to keep the rows of data intact when refreshing?




Thanks in advance for any replies...



I have just installed MS Outlook 2010 and in the previous 2007 version, if I wanted to find all the emails from one person or one the same topic, I just clicked on "from" or "subject" and
they were sorted instantly - the default position on the Outllok 2010 is that all mail is sorted by date (which is normal) however when I try to sort by another means eg "from", the emails go blank in that folder and a red line whizzes across the top presumably indicating that it's sorting them - but it never delivers the new view. You have to cancel it by clicking on a new folder and when you return to the folder you wanted to sort, it still shows that it's sorted by date !! This is really annoying as this is a basic feature which I use all the time. Can someone help me and explain how to fix this problem - or am I doing something wrong ?


Andy C

Warrington, UK



Ok so the report im working with currently has 3 row groups (2 parent groups Region and State and one detail with all the rest of the column headers) and no column groups. so it's set up a little like this:

Region      State     Column 1     Column 2     Column 3

east          state1    blah 1          blah 2            blah 3

                state 2   blah 1          blah 2            blah 3

                             total 1          total 2           total 3

West        state 1    blah 1          blah 2            blah 3

                            total 1           total 2           total 3

Well i need one of the column's with the data in it to have interactive sort on it. However when i turn it on and run the report, it doesn't sort at all. It just sits there. And i can't get sort to work on anything for that table. Even if i put it on the region column it won't sort.

The only thing i can think of is that it is because of the total row that i have in there.

Any help would be much appreciated!!!! thanks!




in my project I'm using a datagridview in the following way:


My data is stored in a datatable.

A dataview: DataView.Table = datatable

A datagridview: datagridview.DataSource=dataview


The data in DataTable is changed dynamically (updated, added, deleted and so on) by events.

The dataview has the Sort method and RowFilter activated.

After binding the dataview, I call the datagridview.ClearSelection, so no Row is selected in the beginning.


My problem: After binding the data, everthing looks fine. But after the first data-update (one row added), there is one row in datagridview selected (but not the added one...). After adding the next row, another row is selected and so on.

In real workflow you will see the selection bar is jumping over the datagridview and also the scrollbar changes the position.

My expected behaviour would be: No row is selected. If a row is added or updated, no selection is there. The scrollbar should remain at its current position. If the user select one row, this row remain selected, until this row will be deleted(then no row will be selected). If a row is selected by user, but the user scrolls down, the scrollbar should remain at its current position and not jump back to the selected row.

When I remove the Sort AND the Filter from the dataview, everything works fine.


I have no plan to solve this issue. I isolated the problem in a very small project (description above) and it is 100% reproducible. I'm not sure, if I'm doing something wrong?! Or is my expectation wrong?


Thank you for your help!



i'm populating a datatable with the results of an SQL query via a dataadapter

After setting a primary key and working with the data i'm then displying the datatable in a DGV

for subsequent queries, i clear the DGV columns & datatable, columns & primary key (see below) before refilling it, which it works fine unless the DGV has been sorted by the user  

dt1.PrimaryKey = Nothing
SQLConnection = New SqlConnection("conectionstring")
SQLCommand = New SqlCommand("query", SQLConnection)
daSQL = New SqlDataAdapter(SQLCommand)
DataGridViewItems.DataSource = dt1

I get an unhandled null reference exception: 'Object reference not set to an instance of an object'

Can anyone please explain what i'm doing wrong, i can't undrstand why sorting the DGV has an effect on the datatable or refiliing it, especially as i'm doing everything i can to clear it ready for re-use.  I don't know what i need to do to be able to reuse the datatable after the DGV has been sorted.


OK I have this sort algorithm, its different from the others I have, and I am trying to make it work with iterators as opposed to the simplistic method usually offered.

Not sure what is wrong

template <class iterator> void gnome(iterator first, iterator last){ // O(n^2)
	iterator pos = first;
	while (pos < last) {
		if ((pos == first) || ((*pos) >= *(pos - 1)))
		else {
			std::iter_swap(pos, pos+1);

The pos iterator starts at zero so I am using first as its initializer as I cannot cast 0 in the usual sense.

Next the conditional is a comparison to zero again, so I used first again as the value.

Seems that it does not work properly and I am not sure what the problem is, any see where I am wrong?




Hi There,

Using Sharepoint designer 2007 and WSS 3.0. I've added a SQL view as a dataformwebpart and whenever I try and sort and group by the 2 fields I need, the sorting displays correctly in sharepoint designer but whenever I browse to the site I get the error message

"Unable to display this Web Part. To troubleshoot the problem, open this Web page in a Windows SharePoint Services-compatible HTML editor such as Microsoft Office SharePoint Designer. If the problem persists, contact your Web server administrator"

I thought this might be caused by the data in the fields to be sorted, some were numeric and some were text, so I altered the SQL view so it converted all to varchar but it still won't sort properly.  I've had this problem many many times with different views, sometimes it sorts perfectly, other times I get this annoying message which doesn't help me find the reason. Can anybody please explain why this is happening, or offer a workaround or solution?

Secondly whenever you insert a dataformwebpart from a SQL View it ignores Aliases and just presents the original field title, this is incredibly annoying as I like most other people in the world in my role work with a relational database where most primary key fields in the major tables are all called No_ or Code, In some cases I can take the field from another table where it is called something else but not always and then I'm left with a view containing 3 columns called No_.

Has anybody found a workaround for this particular quirk of sharepoint designer?


Many thanks in advance for any assistance.





On an Access 2007 datasheet if the selected field is a combo box and I use the Sort A to Z control, I get a sort using the hidden number value instead of the displayed value. I have not been able to find a work around for this that does not cause an error when I edit and save records. Frustrating. Also, I would like a simple way to post this as a bug and to see existing bugs ("known problems") for Access 2007.


I have a little problem with sorting a List<String>.

I have put 4 elements like this and now are trying sort them correct. My example below shows the problem. I am not sure of how sort the names so they comes in this order: "Folder1, Folder2, Folder10, Foler11"  ?

List<String> GetNames = new List<String>();

GetNames .Add("Folder1");
GetNames .Add("Folder10");
GetNames .Add("Folder2");
GetNames .Add("Folder11");

GetNames.Sort(); //Sort the list

The sort comes in this order now which is wrong:

How to sort the list to have this order: ?



I have created a matrix with a toggle option on one of the rows (when the report is initially run this row is hidden).  This row when toggled produces 10 or more rows with data.  In the column headings I have given the user the option to interactively sort through the data that is stored in this row.  The problem that I am having is that when I choose to sort the data after I have toggled to see the data, the report re-renders and the goes back to the un-toggled view.  So I have to re-toggle to see what my sorted data.

I want to be able to view my sorted data without having to toggle back out.

I believe the solution lies in Row visibility "show or hide based on expression".  I just don’t know what expression to use... or if the solution is more complex.

Help please.



I have a problem with sorting an array which contains other arrays. The other arrays have an value in them which I want to sort them after

(you will understand more after looking at my code). I think I'm close to the answer but I've been spending countless of hours trying to figure out the last bit. The error I receive  with current code is "IndexOutOfRange".


            string[] sell1 = { sell1Name, sell1Per, sell1Dist, sell1Sold };
            string[] sell2 = { sell2Name, sell2Per, sell2Dist, sell2Sold };
            string[] sell3 = { sell3Name, sell3Per, sell3Dist, sell3Sold };
            string[] sell4 = { sell4Name, sell4Per, sell4Dist, sell4Sold };
            string[] sell5 = { sell5Name, sell5Per, sell5Dist, sell5Sold };
            string[] sell6 = { sell6Name, sell6Per, sell6Dist, sell6Sold };
            string[] sell7 = { sell7Name, sell7Per, sell7Dist, sell7Sold };
            string[] sell8 = { sell8Name, sell8Per, sell8Dist, sell8Sold };

            string[][] list = new string[][] { sell1, sell2, sell3, sell4, sell5, sell6, sell7, sell8 };

            bool sorted;

                sorted = true;

                foreach (string[] str in list)

                    for (int i = 0; i < list.Length-1; i++)
                        if (Convert.ToInt32(str[i][3]) < Convert.ToInt32(str[i + 1][3]))
                            string[] temp = str;

                            str[i] = str[i + 1];
                            str[i + 1] = Convert.ToString(temp);

                            sorted = false;

            while (!sorted);
            Console.WriteLine("Säljar Namn\tPersonnummer\tDistrikt\tAntal");

            foreach (string[] str in list)
                foreach (string s in str)
                    Console.Write(s + "\t");


<< Previous      Next >>

Microsoft   |   Windows   |   Visual Studio   |   Sharepoint   |   Azure