Apologies for somewhat confusing explanation. I am using Microsoft.Office.Interop.Excel. Purpose for code below is to
1) Iterate all rows in Column B of excel sheet named oSheet1
2) Iterate all rows in Column 0 of datagridview (DTG)
3) If data from Column B and Column 0 matches, then export data in Column 1 of DTG into Column C of excel.
Hence, the data in column 1 of DTG is in reference with data in Column 0 of DTG. And data in Column C of excel will eventually be in reference with Column B of excel. I've inserted some images for easy understanding
I've tried multiple codes for hours and kept getting error. Below are my codes along with errors experienced:
Error: Cannot perform in runtime binding on null reference
for (int i = 1; i <= oSheet1.Columns.Count; i++)
{
string cellvalue = oSheet1.Cells[i, 2].Value.ToString(); //error here
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if ((string)row.Cells[0].Value == cellvalue)
{
for (int j = 0; j < dataGridView1.Rows.Count; j++)
{
oSheet1.Cells[i, 3] = dataGridView1.Rows[j].Cells[1].Value.ToString();
}
}
}
Error: Exception from H result
for (int i = 1; i <= oSheet1.Columns.Count; i++)
{
object cellvalue = oSheet1.get_Range("B:B" + Convert.ToString(i));
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[0].Value == cellvalue)
{
for (int j = 0; j < dataGridView1.Rows.Count; j++)
{
oSheet1.Cells[i, 3] = dataGridView1.Rows[j].Cells[1].Value.ToString();
}
}
}
}
I would appreciate any help. Thank you!!
Try UsedRange.
var range = oSheet1.UsedRange;
int startingRowIndex = range.Row + 1; //to skip the header
for (int rowIndex = startingRowIndex; rowIndex < range.Row + range.Rows.Count; rowIndex++)
{
string cellvalue = range.Cells[rowIndex, 2].Value?.ToString();
...
}
Also, you should perform a null check against the Value property just in case the cell is empty, or uses a null-conditional operator as shown in the code above.
Related
I have a datagridview with several columns and different report types, where I have a method to export the records to Excel spreadsheet, in this datagridview I leave some columns like: visible = false according to the selected report type.
In the export method for spreadsheet I have a validation to consider only visible cells, true but it is not working.
int XLRow = 1;
int XLCol = 1;
// Export header
for (int i = 0; i < datagrid.Columns.Count; i++)
{
if (datagrid.Columns[i].Visible == true)
xlWorkSheet.Cells[XLRow, XLCol++] = datagrid.Columns[i].HeaderText;
}
XLRow = 2;
XLCol = 1;
// Controls for scrolling through records do DataGridView
for (int i = 0; i < datagrid.RowCount; i++)
{
for (int j = 0; j < datagrid.ColumnCount; j++)
{
DataGridViewCell cell = datagrid[j, i];
string conteudo = string.Empty;
if ((cell.Value != null) && (!string.IsNullOrEmpty(cell.Value.ToString())) && cell.Visible == true)
{
conteudo = cell.Value.ToString();
if ((Funcoes.EhNumerico(conteudo)) && (conteudo.Length > 8))
{
conteudo = string.Concat("'", conteudo);
}
xlWorkSheet.Cells[XLRow, XLCol++] = conteudo;
}
XLRow++;
XLCol = 1;
}
}
The spreadsheet leaves with the columns that are visible = false in white, as follows:
How can I resolve this?
In other words… in the first for loop… if the column is not visible… then you DO NOT want to increment i… and this is obviously going to mess up the for loop. Hence my suggestion to create two (2) int variables… int XLRow and int XLColumn, then use those indexes specifically for the WORKSHEET. Then loop through the grid columns as your code does using i and j, however, when a column is found that is not visible, then you DO NOT want to increment the XLCol index.
It will be a challenging juggling the loops i or j variables to also be used as an index into the worksheet columns as they may be completely “different” indexes. This is why I say “separate” them from the git go and keep it simple. Something like…
EDIT per OP comment…
I had the code that “increments” the XLCol “INSIDE” the if statement that checks for a null cell value or an empty string cell value… meaning if the cell is null or empty… then XLCol does not get incremented. The line xlWorkSheet.Cells[XLRow, XLCol++] = conteudo; should be “outside” that if statement. I have edited the code and it should work properly now with “empty” cells.
int XLRow = 1;
int XLCol = 1;
for (int i = 0; i < datagrid.Columns.Count; i++) {
if (datagrid.Columns[i].Visible == true)
xlWorkSheet.Cells[XLRow, XLCol++] = datagrid.Columns[i].HeaderText;
}
XLRow = 2;
XLCol = 1;
for (int i = 0; i < datagrid.RowCount; i++) {
for (int j = 0; j < datagrid.ColumnCount; j++) {
if (datagrid.Columns[j].Visible) {
DataGridViewCell cell = datagrid[j, i];
string conteudo = string.Empty;
if ((cell.Value != null) && (!string.IsNullOrEmpty(cell.Value.ToString()))) {
conteudo = cell.Value.ToString();
if ((Funcoes.EhNumerico(conteudo)) && (conteudo.Length > 8)) {
conteudo = string.Concat("'", conteudo);
}
//xlWorkSheet.Cells[XLRow, XLCol++] = conteudo; <- XLCol incremented ONLY if cell is not null or empty and this is wrong
}
xlWorkSheet.Cells[XLRow, XLCol++] = conteudo;
}
}
XLRow++;
XLCol = 1;
}
In extension to this question, while retrieving the cell value, are there any more advantages other than improving the readability by using the column names instead of column numbers?
for (i = 0; i <= dt.Rows.Count - 1; i++)
{
for (j = 0; j <= dt.Columns.Count - 1; j++)
{
var cell = dt.Rows[i].Field<double>("DoubleColumn");
//var cell = dt.Rows[i][j];
}
}
I am creating a Google DataTable Net Wrapper DataTable from the scratch. But I dont know how to add rows to the datatable. I have progressed to the code as below
Google.DataTable.Net.Wrapper.DataTable GDt = new Google.DataTable.Net.Wrapper.DataTable();
for (int i = 0; i < dtReports.Columns.Count; i++)
{
Google.DataTable.Net.Wrapper.Column gc = new Google.DataTable.Net.Wrapper.Column();
gc.Id = dtReports.Columns[i].Caption.Substring(0, dtReports.Columns[i].Caption.IndexOf("~"));
gc.Label = dtReports.Columns[i].Caption.Substring(dtReports.Columns[i].Caption.IndexOf("~"), dtReports.Columns[i].Caption.Length);
GDt.AddColumn(gc);
for (int j = 0; j < dtReports.Rows.Count; j++)
{
Google.DataTable.Net.Wrapper.Row gr = GDt.NewRow();
// Code to add datatable current column and row value to Google Row
}
}
Not able to find code to add the values to the row and particular column. Help appreciated.
Here is one way you could do it which fits with your existing code:
for (int j = 0; j < dtReports.Rows.Count; j++)
{
// Code to add datatable current column and row value to Google Row
Google.DataTable.Net.Wrapper.Row gr = i == 0 ? GDt.NewRow() : GDt.Rows.ElementAt(j);
gr.AddCell(new Cell(dtReports.Rows[j][i]));
if (i == 0) GDt.AddRow(gr);
}
I am trying to export a database from c# to excel but the first row from the database is not saving in excel.
private void exporttoexcel()
{
Microsoft.Office.Interop.Excel._Application excel = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel._Workbook workbook = excel.Workbooks.Add(Type.Missing);
Microsoft.Office.Interop.Excel._Worksheet worksheet = null;
try
{
worksheet = workbook.ActiveSheet;
worksheet.Name = "ExportedFromDatGrid";
int cellRowIndex = 1;
int cellColumnIndex = 1;
//Loop through each row and read value from each column.
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
{
for (int j = 0; j < dataGridView1.Columns.Count; j++)
{
// Excel index starts from 1,1. As first Row would have the Column headers, adding a condition check.
if (cellRowIndex == 1)
{
worksheet.Cells[cellRowIndex, cellColumnIndex] = dataGridView1.Columns[j].HeaderText;
}
else
{
worksheet.Cells[cellRowIndex, cellColumnIndex] = dataGridView1.Rows[i].Cells[j].Value.ToString();
}
cellColumnIndex++;
}
cellColumnIndex = 1;
cellRowIndex++;
}
}
catch(Exception ex)
{
}
}
here is the code I'm using. could anyone help me ? I am new in coding.
You're not writing out the data but are only writing out column names when the cellColumnIndex is 1, skipping the first row. But after the first row has been processed, the row index will be incremented. Refactor your for-loop to look something like this:
// Add the column names
var index = 0;
foreach(var column in dataGridView1.Columns)
{
worksheet.Cells[0, index] = column.HeaderText;
index++;
}
//Loop through each row and read value from each column.
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
{
for (int j = 0; j < dataGridView1.Columns.Count; j++)
{
// Excel index starts from 1,1. As first Row would have the Column headers, adding a condition check.
worksheet.Cells[cellRowIndex, cellColumnIndex] = dataGridView1.Rows[i].Cells[j].Value.ToString();
cellColumnIndex++;
}
cellColumnIndex = 1;
cellRowIndex++;
}
Please have a look at ClosedXML. It simplifies writing your code, and eliminate the need to have Excel installed on the machine where you want to run this.
I have added a column header to my datagridview from a list in excel. Now I have a dictionary with the key as the column header and value needs to be inserted to the new row. One dictionary per row.
foreach (DataGridViewRow row in dgv_ExitPoints.Rows)
{
for (int j = 0; j < dgv_ExitPoints.Columns.Count; j++)
{
String header = dgv_ExitPoints.Columns[j].HeaderText;
if(exitPointDictionary.ContainsKey(header)
{
???
}
}
}
I have solved it. If anyone is interested in future:
`for (int j = 0; j < dgv_ExitPoints.Columns.Count; j++)
{
String header = dgv_ExitPoints.Columns[j].HeaderText;
if(exitPointDictionary.ContainsKey(header))
{
dgv_ExitPoints.Rows[counter].Cells[j].Value = exitPointDictionary[header].ToString();
}
++counter;
}`