Add Row Dynamically in TableLayoutPanel - c#

I want to add these entries dynamically row by row in TableLayoutPanel in Windows Form in c#
How can I do that?

Try the below code,
// TableLayoutPanel Initialization
TableLayoutPanel panel = new TableLayoutPanel();
panel.ColumnCount = 3;
panel.RowCount = 1;
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 40F));
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 30F));
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 30F));
panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
panel.Controls.Add(new Label() { Text = "Address" }, 1, 0);
panel.Controls.Add(new Label() { Text = "Contact No" }, 2, 0);
panel.Controls.Add(new Label() { Text = "Email ID" }, 3, 0);
// For Add New Row (Loop this code for add multiple rows)
panel.RowCount = panel.RowCount + 1;
panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
panel.Controls.Add(new Label() { Text = "Street, City, State" }, 1, panel.RowCount-1);
panel.Controls.Add(new Label() { Text = "888888888888" }, 2, panel.RowCount-1);
panel.Controls.Add(new Label() { Text = "xxxxxxx#gmail.com" }, 3, panel.RowCount-1);

I know that this question is very old, but someone could find the following as useful:
First of all, note that petchirajan's answer is good, but if you have at least one existent row (titles, for example) and you want to continue the list using the height set using visual editor, and without having to modify the code, you can use this:
private void AddItem(string address, string contactNum, string email )
{
//get a reference to the previous existent
RowStyle temp = panel.RowStyles[panel.RowCount - 1];
//increase panel rows count by one
panel.RowCount++;
//add a new RowStyle as a copy of the previous one
panel.RowStyles.Add(new RowStyle(temp.SizeType, temp.Height));
//add your three controls
panel.Controls.Add(new Label() {Text = address}, 0, panel.RowCount - 1);
panel.Controls.Add(new Label() { Text = contactNum }, 1, panel.RowCount - 1);
panel.Controls.Add(new Label() { Text = email }, 2, panel.RowCount - 1);
}
If you prefer a generic method for a generic table:
private void AddRowToPanel(TableLayoutPanel panel, string[] rowElements)
{
if (panel.ColumnCount != rowElements.Length)
throw new Exception("Elements number doesn't match!");
//get a reference to the previous existent row
RowStyle temp = panel.RowStyles[panel.RowCount - 1];
//increase panel rows count by one
panel.RowCount++;
//add a new RowStyle as a copy of the previous one
panel.RowStyles.Add(new RowStyle(temp.SizeType, temp.Height));
//add the control
for (int i = 0; i < rowElements.Length; i++)
{
panel.Controls.Add(new Label() { Text = rowElements[i] }, i, panel.RowCount - 1);
}
}
You can do this also using a Collection instead of an array using:
private void AddRowToPanel(TableLayoutPanel panel, IList<string> rowElements)
...
Hope this helps.

in foreach example:
int i=0;
foreach (KeyValuePair<string,string> kv in MyCollection)
{
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 20F));
tableLayoutPanel1.Controls.Add(new Label() { Text = kv.Key }, 0, i);
i++;
}

Here are a couple extension methods you can use:
You can call them by doing the following:
TableLayoutPanel tablePanel = new TableLayoutPanel(); //Initialize and do any other construction
tablePanel.AddColumn(null, "Column1");
tablePanel.AddRow(new RowStyle() { SizeType = SizeType.Absolute, Height = 50 }, "RowData1", "RowData2", "RowData3");
public static int AddRow(this TableLayoutPanel table, RowStyle rowStyle = null, params string[] rowData)
{
List<Label> labels = new List<Label>();
rowData.ToList().ForEach(p => labels.Add(new Label() { Text = p }));
return table.AddRow(rowStyle, labels.ToArray());
}
public static int AddRow(this TableLayoutPanel table, RowStyle rowStyle = null, params Control[] rowData)
{
table.RowCount = table.RowCount + 1;
if (rowStyle == null)
rowStyle = new RowStyle(SizeType.AutoSize);
table.RowStyles.Add(rowStyle);
for (int i = 0; i < rowData.Length; i++)
{
if (i > table.ColumnCount - 1)
break;
table.Controls.Add(rowData[i], i, table.RowCount - 1);
}
return table.RowCount - 1;
}
public static int AddColumn(this TableLayoutPanel table, ColumnStyle columnStyle = null, params string[] columnData)
{
List<Label> labels = new List<Label>();
columnData.ToList().ForEach(p => labels.Add(new Label() { Text = p }));
return table.AddColumn(columnStyle, labels.ToArray());
}
public static int AddColumn(this TableLayoutPanel table, ColumnStyle columnStyle = null, params Control[] columnData)
{
table.ColumnCount = table.ColumnCount + 1;
if (columnStyle == null)
columnStyle = new ColumnStyle(SizeType.AutoSize);
table.ColumnStyles.Add(columnStyle);
for (int i = 0; i < columnData.Length; i++)
{
if (i > table.RowCount - 1)
break;
table.Controls.Add(columnData[i], table.ColumnCount - 1, i);
}
return table.ColumnCount - 1;
}

Related

There are three grids, and after clicking on the Grid3 control, then how to get the control values for Grid1 and Grid2. Xamarin

I'm using Grid and trying to make control dynamically in loop.
There are 3 Grids, and after clicking on the Grid3 control, I would like to get the control values of Grid1 and Grid2.
Please see image.
Any help is appreciated. Thanks!
code behind:
Dictionary<string, string[]> myDictionary3 = _Model.getRoomStatusData(_Model.RoomTypesSel, _Model.StartTimeNames);
//Grid 1 x:Name="timelist"
for (int i = 0; i < _Model.StartTimeNames.Length; i++)
{
Label time = new Label() { Text = _Model.StartTimeNames[i], WidthRequest = 80 };
timelist.Children.Add(time, i, 0);
}
//Grid 2 x:Name="roomtype"
for (int i = 0; i < roomtypes.Length; i++)
{
roomtype.RowDefinitions.Add(new RowDefinition());
Label room = new Label() { Text = _Model.RoomTypesSel[i].Name, WidthRequest = 80 };
roomtype.Children.Add(room, 0, i);
}
List<string[]> roomstatu = new List<string[]>()
{
new string[] {"1","2","3","4","5","6"}, new string[] {"1","2","3","4","5","6"},new string[] {"1","2","3","4","5","6"},new string[] {"1","2","3","4","5","6"},new string[] {"1","2","3","4","5","6"},new string[] {"1","2","3","4","5","6"},new string[] {"1","2","3","4","5","6"},new string[] {"1","2","3","4","5","6"}
};
//Grid 3 x:Name="status"
int index = 0;
foreach (var item in roomstatu)
{
status.RowDefinitions.Add(new RowDefinition());
for (int i = 0; i < item.Length; i++)
{
status.ColumnDefinitions.Add(new ColumnDefinition());
Label statuslabel = new Label() { Text = item[i], WidthRequest = 80};
status.Children.Add(statuslabel, i, index);
}
index++;
}
At first, you can get the index of the label user tapped in the status grid. And then you can get the label's row position and column position by the index.
I have done a sample and it worked well, you can try the following code:
int index = 0;
foreach (var item in roomstatu)
{
status.RowDefinitions.Add(new RowDefinition());
for (int i = 0; i < item.Length; i++)
{
status.ColumnDefinitions.Add(new ColumnDefinition());
Label statuslabel = new Label() { Text = item[i], WidthRequest = 80 };
status.Children.Add(statuslabel, i, index);
statuslabel.GestureRecognizers.Add((new TapGestureRecognizer
{
Command = new Command(async (obj) =>
{
Label temp = obj as Label;
Grid gridtemp = temp.Parent as Grid;
int position = gridtemp.Children.IndexOf(temp);
int columnindex = position % timelist.Children.Count;
int rowindex = (position / roomtype.Children.Count) +1;
string timevalue = ((Label)timelist.Children[columnindex]).Text;
string roomtypealue = ((Label)roomtype.Children[rowindex]).Text;
temp.Text = timevalue + "+"+ roomtypealue;
}),
CommandParameter = statuslabel,
}));
}
index++;
}

TableLayoutPanel not showing all data

I have table layout panel. Inside each one I create a Panel to insert two different controls in each cell.
I want to fill TableLayoutPanel with all my data, in this case I have 16 should have 16 different cells. So I try:
private void AddRow(IList<DeliveryBreakdownGetViewModel> rModel)
{
tpnlDeliveryBreakdown.RowCount = rModel.Count / 4; //rModel count = 16
tpnlDeliveryBreakdown.ColumnCount = 4;
var row = 0;
var column = 0;
var fullRow = 1;
for (int i = 0; i < rModel.Count; i++)
{
var panel = new Panel();
Labels.Add(rModel[i].DesignGroupName);
var label = new Label
{
AutoSize = true,
Name = "label" + Labels.Count,
Text = rModel[i].DesignGroupName,
Location = new Point(12, YPos)
};
this.Controls.Add(label);
tpnlDeliveryBreakdown.Controls.Add(panel, column, row);
panel.Controls.Add(label);
DeliveryBreakdownLabelsModel.Add(label);
var numericUpDown = new NumericUpDown
{
Name = "numericUpDown" + Labels.Count,
Maximum = decimal.MaxValue,
Minimum = decimal.MinValue,
Value = Decimal.Round(rModel[i].ContractedAmount, 2),
Location = new Point(12, YPos),
Size = new Size(60, 19),
DecimalPlaces = 2,
Tag = rModel[i].DesignGroupId
};
this.Controls.Add(numericUpDown);
panel.Controls.Add(numericUpDown);
DeliveryBreakdownNumericUpDownModel.Add(numericUpDown);
if (fullRow % 4 == 0)
{
row++;
}
fullRow++;
if(column == 4)
{
column = 0;
}
else
{
column++;
}
}
}
But it only show 2 columns and 7 cells:
Why is not showing all cells and it only show 2 columns instead 4. Regards

How to dynamically scale control size in a TableLayoutPanel

My goal is to have a grid of buttons which represent my 2d array using a TableLayoutPanel.
Currently I can get the correct amount of columns and rows and it adds the buttons in the right place.
The problem I am having is the scaling of the buttons. I've already tried other solutions but they don't seem to work.
Filling the table
int[,] testArr = new int[,] { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }, { 13, 14, 15, 16 } };
tableLayoutPanel_TopView.ColumnCount = testArr.GetLength(0);
tableLayoutPanel_TopView.RowCount = testArr.GetLength(1);
tableLayoutPanel_TopView.AutoSize = true;
for (int y = 0; y < testArr.GetLength(1); y++)
{
for (int x = 0; x < testArr.GetLength(0); x++)
{
Button btn = new Button
{
Text = x.ToString() + "." + y.ToString(),
Dock = DockStyle.Fill,
};
tableLayoutPanel_TopView.Controls.Add(btn);
}
}
Single percHeight = ((Single)1 / (Single)tableLayoutPanel_TopView.RowStyles.Count) * 100;
Single percWidth = ((Single)1 / (Single)tableLayoutPanel_TopView.ColumnStyles.Count) * 100;
foreach (ColumnStyle style in tableLayoutPanel_TopView.ColumnStyles)
{
style.SizeType = SizeType.Percent;
style.Width = percWidth;
}
foreach (RowStyle style in tableLayoutPanel_TopView.RowStyles)
{
style.SizeType = SizeType.Percent;
style.Height = percHeight;
}
TableLayoutPanel settings
this.tableLayoutPanel_TopView.ColumnCount = 1;
this.tableLayoutPanel_TopView.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel_TopView.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel_TopView.Location = new System.Drawing.Point(3, 16);
this.tableLayoutPanel_TopView.Name = "tableLayoutPanel_TopView";
this.tableLayoutPanel_TopView.RowCount = 1;
this.tableLayoutPanel_TopView.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel_TopView.Size = new System.Drawing.Size(638, 463);
this.tableLayoutPanel_TopView.TabIndex = 0;
However, this gives the following result:
Current table
As you can see, the width and the height of each button only seems to make sense starting from the second column and second row. What can I do so that each button has the same size?
Solution
I've fixed it by clearing both the ColumnStyles and RowStyles and adding a new style for each row and column. Each style has it's SizeType set to Percent and the width/height is calculated.
Code
I have replaced testArr with sortedContainers, a collection the function was made for.
// above code hasn't changed
Single percHeight = ((Single)1 / (Single)tableLayoutPanel_TopView.RowStyles.Count) * 100;
Single percWidth = ((Single)1 / (Single)tableLayoutPanel_TopView.ColumnStyles.Count) * 100;
tableLayoutPanel_TopView.ColumnStyles.Clear();
tableLayoutPanel_TopView.RowStyles.Clear();
for (int x = 0; x < sortedContainers.Width; x++)
{
tableLayoutPanel_TopView.ColumnStyles.Add(new ColumnStyle
{
SizeType = SizeType.Percent,
Width = percWidth
});
}
for (int y = 0; y < sortedContainers.Length; y++)
{
tableLayoutPanel_TopView.RowStyles.Add(new RowStyle
{
SizeType = SizeType.Percent,
Height = percHeight
});
}

Add rows to TableLayoutPanel at a given Index

I have TableLayoutPanel and adding rows dynamically. How can I insert the rows with controls at a specific index?
private void AddRowstoTableLayout()
{
for (int cnt = 0; cnt < 5; cnt++)
{
RowStyle newRowStyle = new RowStyle();
newRowStyle.Height = 50;
newRowStyle.SizeType = SizeType.Absolute;
Label lbl1 = new Label();
lbl1.Text = "label-" + (cnt + 1);
TextBox t1 = new TextBox();
t1.Text = "text-" + (cnt + 1);
Label lblMove = new Label();
lblMove.Text = "Move-" + (cnt + 1);
lblMove.MouseDown += new MouseEventHandler(dy_MouseDown);
tableLayoutPanel1.RowStyles.Insert(0, newRowStyle);
this.tableLayoutPanel1.Controls.Add(lbl1, 0, cnt); //correct
this.tableLayoutPanel1.Controls.Add(t1, 1, cnt); //correct
this.tableLayoutPanel1.Controls.Add(lblMove, 2, cnt); //correct
tableLayoutPanel1.RowCount += 1;
}
}
I tried
tableLayoutPanel1.RowStyles.Insert(0, newRowStyle);
but no luck
There is no such function out of the box.
The way is to add a row to your TableLayoutPanel. Then move all controls that are positioned in rows greater equal to your desired row index in a rowindex higher than their current position.
Here how you can do that:
void InsertTableLayoutPanelRow(int index)
{
RowStyle newRowStyle = new RowStyle();
newRowStyle.Height = 50;
newRowStyle.SizeType = SizeType.Absolute;
tableLayoutPanel1.RowStyles.Insert(index, newRowStyle);
tableLayoutPanel1.RowCount++;
foreach (Control control in tableLayoutPanel1.Controls)
{
if (tableLayoutPanel1.GetRow(control) >= index)
{
tableLayoutPanel1.SetRow(control, tableLayoutPanel1.GetRow(control) + 1);
}
}
}

How do I make a 2D list of TextBoxes?

private List<TextBox>[,] textBoxesList = new List<TextBox>[6,3]; // would be my list soon
private TextBox[,] textBoxes = new TextBox[6,3]; // my array of text boxes
public Form1()
{
InitializeComponent();
for (int j = 0; j < textBoxes.Length(0); j++)
{
for (int i = 0; i < textBoxesList.GetLength(1); i++)
{
textBoxes[j,i] = new TextBox();
textBoxes[j,i].Size = new Size(35, 20);
textBoxes[j,i].Font = new Font("Microsoft Sans Serif", 8, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
textBoxes[i].Location = new System.Drawing.Point(90 + j * 50, 50 + i * 30);
textBoxes[j,i].Parent = this;
this.Controls.Add(textBoxes[j,i]);
}
}
}
So this is how I've done it with an array. Now I'm very inexperienced at lists. In fact I never learned lists before but have briefly heard that they can grow/shrink compared to arrays. It would be useful for me to use lists so the user can add a row later on.
Tested this code but it's showing blank.
public partial class Form1 : Form
{
//List<List<TextBox>> li = new List<List<TextBox>>();
List<TextBox> litxt = new List<TextBox>();
public Form1()
{
InitializeComponent();
TextBox txt = new TextBox();
txt.Size = new Size(35, 20);
litxt.Add(txt);
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 3; i++)
{
TextBox txt = new TextBox();
litxt.Add(txt);
}
}
}
For 2D list do it like this
List<List<TextBox>> li = new List<List<TextBox>>();
As you need to make a table of text box use a FlowLayoutPanel of fixed width equal to 3 textboxes
Make a list
List<TextBox> litxt = new List<TextBox>();
Add 3 Text box to litxt
for(int i = 0;i<3;i++)
{
TextBox txt = new TextBox();
txt.Size = new Size(35,20);
litxt.Add(txt);
}
Put this Code on the condition where you want to add 3 TextBox
foreach(TextBox txt in litxt)
{
FlowLayoutPanel.Controls.Add(txt);
}
Put This Code
Add a flowlayout panel to your form and perform this code
public Rough()
{
InitializeComponent();
}
private void Rough_Load(object sender, EventArgs e)
{
}
static int i = 0;
private void button1_Click(object sender, EventArgs e)
{
for(int j = 0; j < 3 ; i++,j++)
{
TextBox txt = new TextBox();
txt.Size = new Size(35, 20);
txt.Name = i.ToString();
flowLayoutPanel1.Controls.Add(txt);
}
}
You can use generic Dictionary and make your own key struct to access the elements.
The key struct MyKey:
public struct MyKey
{
private ushort row;
private ushort col;
public int Row { get { return row; } }
public int Col { get { return col; } }
public MyKey(int row, int col)
{
// check if keys are in range between 0 and ushort.MaxValue
if(row < 0 || row > ushort.MaxValue || col < 0 || col > ushort.MaxValue)
throw new ArgumentOutOfRangeException(string.Format("Arguments row and col cannot be less than 0 or greater than {0}.", ushort.MaxValue));
this.row = (ushort) row;
this.col = (ushort) col;
}
// Overriden GetHashCode() that's used by the Dictionary to search through the keys.
public override int GetHashCode()
{
// we just shift Row by 16 Bits to left and make a bitwise or with Col to generate the Hashcode
return ((int) row << 16) | col;
}
}
And now you can use this key with Dictionary:
var textBoxesList = new Dictionary<MyKey, TextBox>();
var rowCount = 6;
var colCount = 3;
for (int row = 0; row < rowCount; row++)
{
for (int col = 0; col < colCount; col++)
{
var key = new MyKey(row, col);
var textBox = new TextBox();
textBox.Size = new Size(35, 20);
textBox.Font = new Font("Microsoft Sans Serif", 8, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
textBox.Location = new System.Drawing.Point(90 + row * 50, 50 + col * 30);
textBox.Parent = this;
// store the key in the Tag property of the TextBox
// so you can get the row and the column of your textbox with
// var key = (MyKey) textBox.Tag
textBox.Tag = key;
textBoxesList.Add(key, textBox);
this.Controls.Add(textBox);
}
}
If you want to get a TextBox by row 2 and column 4 you can write:
var textbox = textBoxesList[new MyKey(row: 2, col: 4)];
You can also walk though the collection:
foreach (var item in textBoxesList)
{
var row = item.Key.Row;
var col = item.Key.Col;
var textbox = item.Value;
// ...
}
And for example you can search the textBoxesList for TextBoxes in a specific row. Let's say we wanna get all Textboxes in row 2 ordered by the column number:
var textBoxesInRow2 = (from item in textBoxesList
where item.Key.Row == 2
orderby item.Key.Col
select item.Value)
.ToArray();
You need to use
List<List<TextBoxes>>
and
You could use a TextBox[,] for this purpose:
private TextBox[,] textboxes;
public YourClass() {
// Add this after the text boxes have actually been set up...
textboxes = new TextBox[,] {
{textbox00, textbox01, textbox02, ...},
{textbox10, textbox11, textbox12, ...},
,,,
};
}
Then you can access textbox00 as textboxes[0,0], textbox56 as textboxes[5,6], etc.
Assuming each row has the same number of checkboxes (e.g. 3) then you could do it like this:
List<TextBox[3]> textboxes = new List<TextBox[3]>
{
new TextBox[3] { textbox1, textbox2, textbox3 };
new TextBox[3] { textbox4, textbox5, textbox6 };
};
Then when you want to add a new row of checkboxes
textboxes.Add(new TextBox[3] { textbox7, textbox8, textbox9 }; );
Note: The DataGridView control may be a better option than TextBoxes for you.
It gives you that Excel like cell structure and you can easily wire a List to it as the data source.

Categories

Resources