Search code examples
c#winformsflowlayoutpanel

Changing order of controls in flow layout panel during runtime


I have a Windows form on which I put a flow layout panel. I also have a class that reads a local database and returns the corresponding values. Depending on the user input via a button(s) the panel gets filled with other buttons. The amount of these buttons depends on the values in the local database. The buttons are displayed correctly and with the correct information, but the order in which they are displayed is alphabetical even though the data-table, from the database class, is ordered in the correct way (via the numerical value of the "ID" column from the database).

I have also added a data-grid view to check and there the items are displayed in the correct way. I have tried to add a for-each loop but that just seems to randomize the order of the buttons.

Does anybody know how I can get the buttons to be displayed in the correct way, so that the button with the lowest "ID" value gets displayed first.

Here is the code for displaying the buttons:

//set the datagridview with the correct values/names. Order works perfectly
dataGridView_AttackName.DataSource = db.attackIDName(attackCategory, taughtOn);
DataTable dt = db.attackIDName(attackCategory, taughtOn);
//sort datable again because doesnt work from db class
dt.DefaultView.Sort = "ID";
dt.DefaultView.ToTable();

int horizontal = 0;
int vertical = 0;
Button[] buttonArray = new Button[dt.Rows.Count];

for (int items = 0;  items < buttonArray.Length; items++)
{
  buttonArray[items] = new Button();
  buttonArray[items].Size = new Size(150, 50);
  buttonArray[items].Location = new Point(horizontal, vertical);
  buttonArray[items].Name = string.Format("Button_{0}", dt.Rows[items]["ID"].ToString());
  buttonArray[items].Text = dt.Rows[items]["Name"].ToString();
  buttonArray[items].Click += btn_msg;
  if ((items + 1) < buttonArray.Length)
  {
    vertical += 50;
  }
  flowLayoutPanel_AttackName.Controls.Add(buttonArray[items]);
}

//get the correct ID value from the button name and try to order it that way
foreach (Button b in flowLayoutPanel_AttackName.Controls)
{
  string name = b.Name;
  string subname = name.Substring(name.IndexOf("_") + 1);
  int i = Convert.ToInt32(subname);
  flowLayoutPanel_AttackName.Controls.SetChildIndex(b, i);
}

I have searched around on this site but couldn't find anything that worked.


Solution

  • You've correctly sorted the DefaultView by the ID, but then haven't used the results!

    You need to replace, for example, dt.Rows[items]["Name"]with dt.DefaultView[items].Row["Name"]. You then don't need the statement dt.DefaultView.ToTable().

    Full code is below:

            dt.DefaultView.Sort = "ID";
            int horizontal = 0;
            int vertical = 0;
            Button[] buttonArray = new Button[dt.Rows.Count];
    
            for (int items = 0; items < buttonArray.Length; items++)
            {
                buttonArray[items] = new Button();
                buttonArray[items].Size = new Size(150, 50);
                buttonArray[items].Location = new Point(horizontal, vertical);
                buttonArray[items].Name = string.Format("Button_{0}", dt.DefaultView[items].Row["ID"].ToString());
                buttonArray[items].Text = dt.DefaultView[items].Row["Name"].ToString();
                buttonArray[items].Click += btn_msg;
    
                if ((items + 1) < buttonArray.Length)
                {
                    vertical += 50;
                }
    
                flowLayoutPanel_AttackName.Controls.Add(buttonArray[items]);
            }