I'm doing an exercise on asp.net using code generated tables with a very simple code:
protected void btnAceptar_Click(object sender, EventArgs e)
{
tblGenerar.Controls.Clear();
for(int i = 0; i < Convert.ToInt32(txtRows.Text);i++)
{
TableRow rowNew = new TableRow();
tblGenerar.Rows.Add(rowNew);
for (int j = 0; j < Convert.ToInt32(txtCols.Text);j++ )
{
TableCell cellNew = new TableCell();
rowNew.Cells.Add(cellNew);
cellNew.Text = txtTexto.Text;
if (chkMargen.Checked == true)
{
cellNew.BorderStyle = BorderStyle.Inset;
cellNew.BorderWidth = 1;
}
}
}
}
The first time I choose to create border on the table, it works, but next time I choose to generate the table without the borders, the borders from last generated table are still there. Additional cells appears with no borders.
Why does this happen if I'm using Controls.Clear() and how can I solve it?
Thanks.
Put else condition within your code.
else
{
cellNew.BorderStyle = BorderStyle.None;
cellNew.BorderWidth = 0;
}
or you can do something like following.
cellNew.BorderStyle = BorderStyle.None;
if (chkMargen.Checked == true)
{
cellNew.BorderStyle = BorderStyle.Inset;
cellNew.BorderWidth = 1;
}
And you are done.
This is because once your Table is generated you can not apply changes on them and to do that you need to explicitly remove border first and then apply if check box is checked.
Related
I don't know how I could connect these two files to work.
output.cs file
public static void PrintGrid(Grid grid)
{
for (int j = 0; j <= grid.GetHeight(); j++)
{
TableRow row = new TableRow();
for (int i = 0; i <= grid.GetWidth(); i++)
{
TableCell cell = new TableCell();
cell.Text = grid.Get(i, j);
row.Cells.Add(cell);
}
Table1.Rows.Add(row);
}
}
Form1.aspx.cs file
protected void Button1_Click(object sender, EventArgs e)
{
//other code
InOut.PrintGrid(grid);
}
I tested it and wrote it in Button1_Click class ant it works fine, but in some way I need to write this fragment in another cs file and print this table in aspx.
Well, your static class does NOT have Table1 defined.
So, say this:
public static class GridOutPut
{
public static void PrintGrid(GridView grid, DataTable MyTable)
{
for (int j = 0; j <= grid.Rows.Count; j++)
{
TableRow row = new TableRow();
for (int i = 0; i <= grid.Columns.Count; i++)
{
TableCell cell = new TableCell();
cell.Text = grid.Rows[i].Cells[j].Text;
row.Cells.Add(cell);
}
MyTable.Rows.Add(row);
}
}
}
(and don't use "output", as that is far to common of a name - and output used for all kind of things!!).
So, now your code say is like this:
DataTable dt = new DataTable();
// dt.Columns.Add() or whatever.
GridOutPut.PrintGrid(GridView1, dt);
So, pass the grid AND the table to that routine.
Of course the above is "air code", but it should suffice for the approach here.
So, you need to pass both the grid variable (instance), (I don't know what you using), and then the table
I am working on a Tic Tac Toe simulator for a class and have run into an issue.
I created a 2-dimensional array to simulate the board and populate it with either 0 or 1 in all the boxes.
The issue I am having is getting those numbers to apply to the labels I have created (a1, a2, a3, b1, b2, etcetera).
Is there a way that my nested for loops can have each element in the array apply to a new label? I can't seem to find anything in my book or online about this.
Here is my related code:
private void newBTN_Click(object sender, EventArgs e)
{
Random rand = new Random();
const int ROWS = 3;
const int COLS = 3;
int [,] board = new int[ROWS, COLS];
for (int row = 0; row < ROWS; row++)
{
for (int col = 0; col < COLS; col++)
{
board[row, col] = rand.Next(1);
}
}
}
What are the names of the labels? I assumed below that the labels are Label0_0, Label0_1, Label1_1 and so on... This way you can find them using the row and column values.
You want to find the Label control on your form dynamically, because you don't know the name in advance while coding.
If you know the name in advance you just say: label1.Text = "1";.
But in your case, you are trying to find a particular control in each iteration of the loop. So you need to have a name for the labels so you can find them using Form.Controls.Find(string, bool) like this:
var row = 4;
var col = 6;
var l = this.Controls.Find("Label" + row.ToString() + "_" + col.ToString(), false).FirstOrDefault() as Label;
if (l == null)
{
//problem... create label?
l = new Label() { Text = "X or O" }; //the position of this need to be set (the default is 0,0)
this.Controls.Add(l);
}
else
{
l.Text = "X or O";
}
Your board stores integers, which is an internal representation of your game state. You can create a UniformGrid that holds Label for your game GUI. The code below returns a grid based on your current board. You need to add this returned grid to your MainWindow (or whatever you use) to see it.
private UniformGrid fillLabels(int[,] board)
{
int numRow = board.GetLength(0);
int numCol = board.GetLength(1);
UniformGrid g = new UniformGrid() { Rows = numRow, Columns = numCol };
for (int i = 0; i < numRow; i++)
{
for (int j = 0; j < numCol; j++)
{
Label l = new Label();
l.Content = (board[i, j] == 0) ? "O" : "X";
Grid.SetRow(l, i);
Grid.SetColumn(l, j);
g.Children.Add(l);
}
}
return g;
}
First, do not re-create (and re-initialize) Random each time you need it: it makes generated sequences skewed badly:
private static Random s_Rand = new Random();
Try not implement algorithm in the button enent directly, it's a bad practice:
private void CreateField() { ... }
private void newBTN_Click(object sender, EventArgs e) {
CreateField();
}
putting all together:
private static Random s_Rand = new Random();
private void ApplyLabelText(String name, String text, Control parent = null) {
if (null == parent)
parent = this;
Label lb = parent as Label;
if ((lb != null) && (String.Equals(name, lb.Name))) {
lb.Text = text;
return;
}
foreach(Control ctrl in parent.Controls)
ApplyLabelText(name, text, ctrl);
}
private void CreateField() {
for (Char row = 'a'; row <= 'c'; ++row)
for (int col = 1; col <= 3; ++col)
ApplyLabelText(row.ToString() + col.ToString(), s_Rand.Next(1) == 0 ? "O" : "X");
}
private void newBTN_Click(object sender, EventArgs e) {
CreateField();
}
How about you skip the INTEGER board and go directly to a Label array?
You can then do the following to loop trough all of them:
Label[,] listOfLabels; // Do also initialize this.
foreach(Label current in listOfLabels)
{
current.Text = _rand.Next(2) == 0 ? "0" : "X";
}
I have a Class(Conatiner) object in a tablelayoutpanel cell. I want to access that textfield in that specific field. How can I take the values on a button click?
I want to access the 1 2 3 with the Channel and the X and Y values. But I do not know the number objects in the tableLayoutPanel
Here is the code I have written so far
private void masterTab1_SaveButton_Click(object sender, EventArgs e)
{
var colWidths = this.MatrixPanel.GetColumnWidths();
var rowHeights = this.MatrixPanel.GetRowHeights();
int col = -1, row = -1;
int offset = 0;
for (int iRow = 0; iRow < this.MatrixPanel.RowCount; ++iRow)
{
offset += rowHeights[iRow];
row = iRow;
for (int iCol = 0; iCol < this.MatrixPanel.ColumnCount; ++iCol)
{
offset += colWidths[iCol];
col = iCol;
var myCellControl = MatrixPanel.GetControlFromPosition(col, row);
if (myCellControl is Container)
{
Adapter.insertposition(RackID, row, col, //Want the Channel Value , "Ready");
}
}
}
}
if your "Container" class is properly setup/has all the properties or controls you need to get the information you want, then i believe what you are looking for is this:
if (myCellControl is Container)
{
Container tmp = myCellControl as Container;
//after this point, you can reference the controls/properties of your
//Container class/control using tmp... see example below as i do not know
//what your Container control exposes as far as properties are concerned.
Adapter.insertposition(RackID, row, col, tmp.ChannelValue, "Ready");
}
I have TableLayoutPanel that I programatically add Rows to. The User basically choses a Property and that is then displayed in the table along with some controls. I think I have a general understanding problem here and I will try to explain it.
One of the Controls in every row is a 'delete'-Button. That button should delete the row it is in. What I did is add an eventhandler to the button and set the current rowcount.
deleteTalent.Click += (sender, e) => buttonClickHandler(numberOfRows);
Code of the handler:
private void buttonClickHandler(int rowCount)
{
int count = rowCount - 1;
for (int i = count; i < (count + 5); i++)
{
balanceTable.Controls.RemoveAt(count);
}
balanceTable.RowStyles.RemoveAt(count);
balanceTable.RowCount--;
}
I looked at it for hours and played around. But I can't find a working clean solution. I'm also pretty new to C#
Here's the complete Function that creates a new row:
private void addBalanceItems(ToolStripMenuItem item)
{
int numberOfRows = balanceTable.RowCount;
if (numberOfRows > 1)
{
balanceTable.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.AutoSize));
}
balanceTable.Height = numberOfRows * 45;
Steigerungsrechner rechner = new Steigerungsrechner();
string tag = item.Tag.ToString();
//change that asap :(
if (tag == "A") { rechner.column = 1; }
if (tag == "B") { rechner.column = 2; }
if (tag == "C") { rechner.column = 3; }
if (tag == "D") { rechner.column = 4; }
if (tag == "E") { rechner.column = 5; }
if (tag == "F") { rechner.column = 6; }
if (tag == "G") { rechner.column = 7; }
if (tag == "H") { rechner.column = 8; }
Label talentName = new Label();
talentName.Text = item.Text;
talentName.Height = standardHeight;
talentName.TextAlign = ContentAlignment.MiddleLeft;
talentName.AutoSize = true;
Label cost = new Label();
cost.TextChanged += (sender, e) => costChangeHandler(cost);
cost.Height = standardHeight;
cost.TextAlign = ContentAlignment.MiddleLeft;
TextBox startValue = new TextBox();
startValue.TextChanged += (sender, e) => startValueChangeHandler(rechner, startValue, cost);
startValue.Height = standardHeight;
startValue.TextAlign = HorizontalAlignment.Center;
TextBox endValue = new TextBox();
endValue.TextChanged += (sender, e) => endValueChangeHandler(rechner, endValue, cost);
endValue.Height = standardHeight;
endValue.TextAlign = HorizontalAlignment.Center;
Button deleteTalent = new Button();
deleteTalent.Text = "x";
deleteTalent.Click += (sender, e) => buttonClickHandler(numberOfRows);
deleteTalent.Height = standardHeight;
balanceTable.Controls.Add(talentName);
balanceTable.Controls.Add(startValue);
balanceTable.Controls.Add(endValue);
balanceTable.Controls.Add(cost);
balanceTable.Controls.Add(deleteTalent);
balanceTable.Visible = true;
balanceTable.RowCount++;
}
Any help would be greatly appreciated! :)
Yeah, removing an arbitrary row from a TableLayoutPanel is not at all intuitive. They really screwed up the design on this one.
The only way to remove rows is by setting the RowCount property. This alone is strange enough; that property sure seems like it should be read-only and code that does this looks wrong to me every time I see it.
But beyond that, the consequence of this design is that you cannot remove rows from the middle. Resetting the RowCount property will just cause rows to be lopped off of the bottom.
The workaround is a bit unwieldy, with multiple steps to get wrong:
Remove the controls from the row you want to delete
If applicable, move those controls to to another row.
Move all of the controls in the other rows that come after the row you wish to delete up a row.
Finally, remove the last row by decrementing the value of the RowCount property.
A quick Google search reveals that someone has written and shared code purporting to do this. It's in VB.NET, but that should be easily translated into your native dialect.
I'll admit that I've been known to just punt and set the RowHeight of the row I wish to "remove" to 0. This way, autosizing does the work for you. You probably still want to remove the controls it contains, though.
Here is a static class that can help you remove any row by it's index:
using System.Windows.Forms;
public static class TableLayoutHelper
{
public static void RemoveArbitraryRow(TableLayoutPanel panel, int rowIndex)
{
if (rowIndex >= panel.RowCount)
{
return;
}
// delete all controls of row that we want to delete
for (int i = 0; i < panel.ColumnCount; i++)
{
var control = panel.GetControlFromPosition(i, rowIndex);
panel.Controls.Remove(control);
}
// move up row controls that comes after row we want to remove
for (int i = rowIndex + 1; i < panel.RowCount; i++)
{
for (int j = 0; j < panel.ColumnCount; j++)
{
var control = panel.GetControlFromPosition(j, i);
if (control != null)
{
panel.SetRow(control, i - 1);
}
}
}
var removeStyle = panel.RowCount - 1;
if (panel.RowStyles.Count > removeStyle)
panel.RowStyles.RemoveAt(removeStyle);
panel.RowCount--;
}
}
One thing to mention: controls that we get via panel.GetControlFromPosition(...) must be visible or it will return null instead of invisible controls.
Remove existing controls of rowCount at first
for(int i = 0; i < panel.ColumnCount; i++){
Control Control = panel.GetControlFromPosition(i, rowCount);
panel.Controls.Remove(Control);
}
Then remove row
panel.RowStyles.RemoveAt(rowCount-1);
Removing complete Table -
tableLayoutPanel1.Controls.Clear();
tableLayoutPanel1.RowStyles.Clear();
Set your Headline of the Table again -
tableLayoutPanel.RowCount = 1;
tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 20F));
tableLayoutPanel.Controls.Add(new Label() { Text = "MONTH", Font = new Font("Century Gothic", 12, FontStyle.Bold), ForeColor = Color.LightGray }, 0, tableLayoutPanel.RowCount - 1);
tableLayoutPanel.Controls.Add(new Label() { Text = "YEAR", Font = new Font("Century Gothic", 12, FontStyle.Bold), ForeColor = Color.LightGray }, 1, tableLayoutPanel.RowCount - 1);
tableLayoutPanel.Controls.Add(new Label() { Text = "MEASURED WAFERS", Font = new Font("Century Gothic", 12, FontStyle.Bold), ForeColor = Color.LightGray }, 2, tableLayoutPanel.RowCount - 1);
3 Columns - 1 Row
Maybe someone can use my codesnipped, works proper good...
You cannot completely delete a row on tablelayoutpanel but there is a workaround:
Remove all the controls in the row, easier if you know the names of the controls cause you can call the dispose method.
Set the height of the row to maybe 2px using the row style method
(e.g. tablelayoutpanel1.Rowstyle(index).height=2)
For me this worked wonders the, row was completely collapsed the row regardless of the row index.
I am trying to populate my DataGridView with custom columns imported from Excel. This should be easy but for the life of me, I am stuck in a brainlock. I should be able to select the specific columns (works), send the column headers to my excel class to parse the data from that column (works), send the parsed data to a List (works) and then import the data to the datagridview by setting my DataSource as my List (I am creating the column header text, but the code is creating a column called Value and adding my data to it). Here is my code that is creating the problem:
private void btnCreateTable_Click(object sender, EventArgs e)
{
List<StringValue>[] listArr = new List<StringValue>[columnCount];
ExcelClass getData = new ExcelClass();
tabControl1.SelectedTab = tabDataTable;
dgv.Visible = true;
DataGridViewTextBoxColumn t = new DataGridViewTextBoxColumn();
//dgvSelectedHeaders.Columns[i].Name = selectedHeaders[i];
for (int i = 0; i < columnCount; i++)
{
//dgv[i].DataSource = getData.GetDataFromExcel(headersArr[i], path);
listArr[i] = getData.GetDataFromExcel(selectedHeaders[i], path);
t.Name = selectedHeaders[i];
t.HeaderText = selectedHeaders[i];
dgv.Columns.Add(t);
dgv.DataMember = "String";
dgv.DataSource = listArr[i];
for (int j = 0; j < getData.RowCount; j++)
{
dgv.Rows.Add();
for (int k = 0; k < getData.RowCount; k++)
{
dgv[k, j].Value = listArr[j][k].ToString();
}
}
}
If I select more than one column, it shows the first one but I get an error after the first one at row dgv.Columns.Add(t); ... InvalidOperationException, provided column already belongs to the DataGridView control... I know these are two questions, but I think they are tied together somehow.
Thanks in advance, and if you need more code, let me know.
I think you need to create a new DataGridViewColoumn for each column
for (int i = 0; i < columnCount; i++)
{
DataGridViewTextBoxColumn t = new DataGridViewTextBoxColumn();
// ...
dgv.Columns.Add(t);
}
rather than reusing it.