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
Related
I create text boxes dynamically and use to store the data. How do I get the text boxes id and how to get total value from all text boxes?
I used this code for creating dynamic text boxes:
for (int B = 0; B < 4; B++)
{
TextBox tb = new TextBox();
int i = TextBoxes.Count + 1;
tb.Location = new Point(0, i * 28);
tb.Width = 80;
tb.Name = "ID" + i;
tb.Text = i.ToString();
TextBoxes.Add(tb);
panel1.Controls.Add(tb);
}
you can try this if you are sure that all values will only hold numbers
var allTexboxes = this.Controls.OfType<TextBox>();
var sumOfAllTextBoxes = allTexboxes.Sum(x => Convert.ToInt32(x.Text));
if not
var allTexboxes = this.Controls.OfType<TextBox>();
var sum = 0;
foreach (var allTexbox in allTexboxes)
{
if (int.TryParse(allTexbox.Text, out var i))
{
sum = sum + i;
}
}
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
});
}
I have started developing a windows phone application where I'm creating the row in a grid dynamically. Upon some conditions I need to the delete the row and all its content in that row.
Here is my sample code.
result = e.Parameter as string;
string[] acst = result.Split('|');
int j = 0;
root2.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(10) });
for (int i = 6; i < acst.Length - 1; i++)
{
TextBlock mytextblock = new TextBlock();
mytextblock.Name = "txtDetails" + root2.Children.Count + 1;
mytextblock.Text = acst[i + 1];
if (mytextblock.Text != "")
{
if (mytextblock.Text.Trim() != "0.00") // if result is 0.00 then i have to delete all the content in that row.
{
if (j == 0)
{
mytextblock.FontSize = 14;
mytextblock.IsTextScaleFactorEnabled = false;
mytextblock.HorizontalAlignment = HorizontalAlignment.Stretch;
mytextblock.VerticalAlignment = VerticalAlignment.Center;
Grid.SetColumn(mytextblock, 1);
Grid.SetRow(mytextblock, (i) / 6);
j++;
}
else if (j == 1)
{
mytextblock.FontSize = 14;
mytextblock.IsTextScaleFactorEnabled = false;
mytextblock.Visibility = Visibility.Collapsed;
mytextblock.HorizontalAlignment = HorizontalAlignment.Center;
mytextblock.VerticalAlignment = VerticalAlignment.Center;
Grid.SetColumn(mytextblock, 2);
Grid.SetRow(mytextblock, (i) / 6);
j++;
}
else if (j == 2)
{
mytextblock.FontSize = 14;
mytextblock.IsTextScaleFactorEnabled = false;
mytextblock.TextWrapping = TextWrapping.Wrap;
mytextblock.HorizontalAlignment = HorizontalAlignment.Left;
mytextblock.VerticalAlignment = VerticalAlignment.Center;
Grid.SetColumn(mytextblock, 3);
Grid.SetRow(mytextblock, (i) / 6);
j=0;
root2.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(60) });
}
}
root2.Children.Add(mytextblock);
}
else
{
root2.RowDefinitions.RemoveAt((i / 6)); // here I'm getting Arugument Exception
}
}
for example if I get mytextblock.text = 0.00 in third column (j=2 in this case). i need to remove the content in column 1 and 2 or to delete thst particular row.
I've tried "root2.RowDefinitions.RemoveAt" but there I am getting Arugument Exception. Where I'm missing?
Any help would be highly appreciated.
Initially your grid has 1 row you are creating whose index is 0. But when you are executing
root2.RowDefinitions.RemoveAt((i / 6));
actually you are getting
root2.RowDefinitions.RemoveAt(1);
So you should use
root2.RowDefinitions.RemoveAt((i / 6)-1); would solve the exception
To answer the second question the code is too much confusing. I am listing some
1: Why are you starting loop from 6
2: Why dividing i/6
3: What exactly you are getting from result
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;
}
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.