Adding rows and columns programmatically [duplicate] - c#

I'm sending values from one form to another form, then want to display in dgv,
I'm trying this, there is no error during execution, bt it does not show data in dgv..
lineItemsDGV.Rows.Add();
int RowIndex = lineItemsDGV.RowCount - 1;
DataGridViewRow NewRow =lineItemsDGV.Rows[RowIndex];
NewRow.Cells[0].Value = item.Product_id;
NewRow.Cells[1].Value = item.product_name;
NewRow.Cells[2].Value = item.specification;
NewRow.Cells[3].Value = item.unit_price;
NewRow.Cells[4].Value = item.unit_price * 1;

You're close.
What you can do is use the return value of your call to DataGridViewRowCollection.Rows.Add() method, which is the index value of the just added row.
Change your code to this:
int RowIndex = lineItemsDGV.Rows.Add();
DataGridViewRow NewRow = lineItemsDGV.Rows[RowIndex];
NewRow.Cells[0].Value = item.Product_id;
NewRow.Cells[1].Value = item.product_name;
NewRow.Cells[2].Value = item.specification;
NewRow.Cells[3].Value = item.unit_price;
NewRow.Cells[4].Value = item.unit_price * 1;

This is how I would do it:
DataRow rowToAdd= myTable.NewRow();
rowToAdd["ProductId"] = item.Product_id;
rowToAdd["ProductName"] = item.product_name;
rowToAdd["Specification"] = item.specification;
rowToAdd["UnitPrice"] = item.unit_price;
myTable.Add(rowToAdd);
And bind the datatable to the gridview.

I know this thread is old, but I found this page helpful today and this is how I accomplished adding a new row which is different than the previous solutions.
Assumption:
datagridview has columns specified at design time. In my case I had 3 text columns.
The solution is to use the DataGridViewRowCollection.Add functionality and pass a parameter array that contains a list of each column value separated by a comma.
DataGridView1.Rows.Add("Value 1", "Value 2", "Value3")
Using this approach, there's no need to use the BeginEdit, Update or Refesh dgv functions.

Related

Adding Array to Existing DataTable

I have a DataTable, dtHOURS, that consists of two columns of data passed from an SQL database and I am trying to include a third column that consists of calculated values within the array, hours. I've looked at many similar asked questions, but none of the solutions seem to work in my case. I've confirmed that the correct values are being stored in the array, but I can't seem to populate those values within column "Total Hours". All the row data comes out blank for this column.
Any help would be appreciated.
Thank you in advance.
//Create new column and row for the "Total Hours" in data table
DataColumn TotalHoursCol;
DataRow TotalHoursRow;
// Create new DataColumn, set DataType,
// ColumnName and add to DataTable.
TotalHoursCol = new DataColumn();
TotalHoursCol.DataType = System.Type.GetType("System.Double");
TotalHoursCol.ColumnName = "Total Hours";
// Add the Column to the Table.
dtHOURS.Columns.Add(TotalHoursCol);
//This loop calculates the total hours for all jobs and adds them to the data table
for (int i = 1; i < numberOfRecordsHours; i++)
{
//Console.WriteLine(dtHOURS.Rows[i]["ID"]);
//Console.WriteLine(dtHOURS.Rows[i]["ACT_RUN_HRS"]);
if ((Convert.ToString(dtHOURS.Rows[i]["ID"])) == (Convert.ToString(dtHOURS.Rows[i-1]["ID"])))
{
hours[i] = (Convert.ToDouble(dtHOURS.Rows[i]["ACT_RUN_HRS"])) + (hours[i-1]);
//Console.WriteLine(hours[i]);
}
else
{
hours[i] = 0;
//Console.WriteLine("NEW JOB");
}
TotalHoursRow = dtHOURS.NewRow();
TotalHoursRow["Total Hours"] = hours[i];
dtHOURS.Rows.Add(TotalHoursRow);
//Console.WriteLine(dtHOURS.Rows[i]["Total Hours"]);
}
If I am understanding the problem correctly, it looks like you are adding a new row instead of assigning to your new column.
Instead of
TotalHoursRow = dtHOURS.NewRow();
TotalHoursRow["Total Hours"] = hours[i];
dtHOURS.Rows.Add(TotalHoursRow);
Just put
dtHOURS.Rows[i]["Total Hours"] = hours[i];

Change values of Cells in a Filtered DataGridView

I have DataGridView with a Column named flag and others.
When I apply a filter:
dataGridView2.DataSource =
new DataView(ds, "flag = 1", "tw_Name DESC", DataViewRowState.CurrentRows);
it shows only Rows where he Column flag value is equal to 1, but...
when I try to programmatically change this value, for example in 6 checked rows:
foreach (DataGridViewRow row in dataGridView2.Rows)
{
if (Convert.ToBoolean(row.Cells["zazn"].Value))
{
row.Cells["flags"].Value = 0;
}
}
three Rows disappear, one Row changes its value, two Rows do not change.
Next, when I click any Row, I get only 2 of the desired changes.
Since you're working with a DataTable, it's preferable that you modify the values of its Rows' content instead the DataGridView Cells while a Filter is active on the DataTable's DataView.
This causes the immediate propagation of the data changes, which your DataGridView will acknowledge. Not guaranteed if you do the opposite, trying to propagate the Control's changes to the DataSource.
This may go against the internal mechanics used by the Control to notify the changes to its DataSource: a DataGridView notify value changes of its Cells after the Cell edit has completed and validation has been performed.
You could try to call [DataGridView].EndEdit() and Validate(), it doesn't mean that in any circumstance the Control and the DataSource will synchronize when you expect it to happen.
Set the Filter and order the View:
Note that the order is applied to the DefaultView, not the DataTable. The Rows' order in the DataTable remains unchanged.
In your sample code, a filter is set to flag = 1, while you use another name for the Column in row.Cells["flags"].
var dView = (dataGridView2.DataSource as DataTable).DefaultView;
dView.RowFilter = "flag = 1";
dView.Sort = "tw_Name DESC";
When you need to change values in some of the Rows, access the DataTable using the DataGridView.DataSource and cast it to DataTable (or BindingSouce or whatever other source of data you have used).
You can now loop the DataRows and set new values to some Columns base on a condition, as in this case:
var dt = dataGridView2.DataSource as DataTable;
for (int i = 0; i <= dt.Rows.Count - 1; i++) {
var row = dt.Rows[i];
if (row["zazn"] != DBNull.Value && (bool)row["zazn"]) {
row["flag"] = 0;
}
}
You could do the same thing using the DataGridView.Row.DataBoundItem, which is a DataRowView in this case, looping backwards (to only loop the visible Rows):
var dt = dataGridView2.DataSource as DataTable;
//BACKWARDS - also assuming there's a NewRow, so Rows.Count - 2
for (int i = dataGridView2.Rows.Count - 2; i >= 0; i--) {
var row = (dataGridView2.Rows[i].DataBoundItem as DataRowView).Row;
if (row["zazn"] != DBNull.Value && (bool)row["zazn"]) {
row["flag"] = 0;
}
}
If you do the same but with a forward loop:
for (int i = 0; i < dataGridView2.Rows.Count - 1; i++) { ... }
you're in the same situation as before.

Combobox default value is always SQL table value - c#

I am retrieving a datatable from a Stored Procedure and a Combobox is showing that data but I want to show -Select Program- as default value of Combobox but it is always showing the first record of datatable.
InitializeComponent();
cbxProgram.Items.Insert(0, "-SELECT PROGRAM-");
cbxProgram.SelectedIndex = 0;
cbxProgram.DataSource = SomeBL.GetProgramName().Tables[0];
cbxProgram.DisplayMember = "ProgramName";
cbxType.DataSource = SomeBL.GetType("").Tables[0].DefaultView;
cbxType.DisplayMember = "Type";
cbxNumber.DataSource = SomeBL.GetNumber("", "").Tables[0].DefaultView;
cbxNumber.DisplayMember = "Number";
cbxType.Enabled = false;
cbxType.Enabled = false;
You have to add your custom Row to your Table before binding.
I didn't test this, but it should look something like this:
DataTable dt = SomeBL.GetProgramName().Tables[0];
DataRow dr = dt.NewRow();
dr[0] = "-SELECT PROGRAM-"; // Look at the index of your desired column
dt.Rows.InsertAt(dr,0); // Insert on top position
cbxProgram.DataSource = dt;
cbxProgram.SelectedIndex = 0;
cbxProgram.DisplayMember = "ProgramName";
By using Datasource property, you delete the data exist in the first place. You should insert "-SELECT PROGRAM-" line after you fill the combobox from datasource.
Try this:
cbxProgram.DataSource = SomeBL.GetProgramName().Tables[0];
cbxProgram.DisplayMember = "ProgramName";
cbxProgram.Items.Insert(0, "-SELECT PROGRAM-");
cbxProgram.SelectedIndex = 0;
If it doesn't let you add another line after setting datasource, you may consider adding the line to the source datatable. (I don't recommend adding it from SQL database by changing your stored procedure.)
Check this pseudocode:
SomeBL.GetProgramName().Tables[0].Rows.Add(new DataRow(0, "-SELECT PROGRAM-"));
cbxProgram.DisplayMember = "ProgramName";
cbxProgram.Items.Insert(0, "-SELECT PROGRAM-");
cbxProgram.SelectedIndex = 0;

How to set Cell value of DataGridViewRow by column name?

In windows forms, I'm trying to fill a DataGridView manually by inserting DataGridViewRows to it, so my code looks like this:
DataGridViewRow row = new DataGridViewRow();
row.CreateCells(dgvArticles);
row.Cells[0].Value = product.Id;
row.Cells[1].Value = product.Description;
.
.
.
dgvArticles.Rows.Add(row);
However, I would like to add the Cell value by column name instead of doing it by the index, something like this:
row.Cells["code"].Value = product.Id;
row.Cells["description"].Value = product.Description;
But doing it like that throws an error saying it couldn't find the column named "code".
I'm setting the DataGridView columns from the designer like this:
Am I doing something wrong? How can I accomplish what I want to do?
So in order to accomplish the approach you desire it would need to be done this way:
//Create the new row first and get the index of the new row
int rowIndex = this.dataGridView1.Rows.Add();
//Obtain a reference to the newly created DataGridViewRow
var row = this.dataGridView1.Rows[rowIndex];
//Now this won't fail since the row and columns exist
row.Cells["code"].Value = product.Id;
row.Cells["description"].Value = product.Description;
I tried it too and got the same result. This is a little verbose, but it works:
row.Cells[dataGridView1.Columns["code"].Index].Value = product.Id;
When you use the ColumnName indexer of the DataGridViewCellCollection, internally it tries to get the column index using the ColumnName from the owning/parent DataGridView of this DataGridViewRow instance. In your case the row hasn't been added to the DataGridView and hence the owning DataGridView is null. That's why you get the error that It couldn't find the column named code.
IMO the best approach (same as Derek's) would be to the add the row in the DataGridView and use the returned index to the get the row instance from the grid and then use the column name to access the cells.
The problem is that referencing cells by name doesn't work until the row is added to the DataGridView. Internally it uses the DataGridViewRow.DataGridView property to get at the column names, but that property is null until the row is added.
Using C#7.0's local function feature, the code can be made halfway readable.
DataGridViewRow row = new DataGridViewRow();
row.CreateCells(dgvArticles);
DataGridViewCell CellByName(string columnName)
{
var column = dgvArticles.Columns[columnName];
if (column == null)
throw new InvalidOperationException("Unknown column name: " + columnName);
return row.Cells[column.Index];
}
CellByName("code").Value = product.Id;
CellByName("description").Value = product.Description;
.
.
.
dgvArticles.Rows.Add(row);
Another alternative:
Suppose the name of your DataGridView is dataGridView1.
var row = new DataGridViewRow();
// Initialize Cells for this row
row.CreateCells(_dataGridViewLotSelection);
// Set values
row.Cells[dataGridView1.Columns.IndexOf(code)].Value = product.Id;
row.Cells[dataGridView1.Columns.IndexOf(description)].Value = product.Description;
// Add this row to DataGridView
dataGridView1.Rows.Add(row);

Inserting an empty row in DataGridView

I want to introduce a graphical separation between group of rows in a DataGridView.
Which are the options I have:
- Should I introduce an empty row?
- Should I work with borders and/or the paint methods ?
This increases the lower border of the row at specified [Index]:
DataGridViewRow row = dataGridView1.Rows[Index];
row.DividerHeight = 1;
Note that DividerHeigth uses the space of the row, so if you set it to 10 it can cover half row (for me, 1 is enough).
There is also DividerWidth property to separate groups of columns.
grid.Rows.Insert(index, 1);
var addedRow = grid.Rows[index];
This inserts 1 empty templated row at 'index'.
With the Rows.Add() method you add a new row, you can obtain a reference to it by using:
var newRow = dg.Rows[dg.Rows.Add()];
So you can manipulate your new row after, example:
newRow.Cells["myColumn"].Value = "asd";
DataGridViewRow DGVR= (DataGridViewRow)yourDataGridView.Rows[0].Clone();
DGVR.Cells[0].Value = "XYZ";
DGVR.Cells[1].Value = 50.2;
yourDataGridView.Rows.Add(DGVR);

Categories

Resources