Export DataTable to Excel Sheet - Getting Empty Rows When Creating - c#

I have a dataset that consists of 6 tables. When I place them into my method below, it works flawlessly on the first table. However, I notice in the second table the second row (under the columns) is blank and then the table data is shown. This is the same for table three only this time there are two rows which are blank. This increases the blank row as each remaining table is built. I verified that the tables themselves do not have these empty rows. I am hoping that someone here would be so kind to look at this code and let me know what would be the cause of this.
public Excel.Application PrepareForExport(System.Data.DataSet ds)
{
object missing = System.Reflection.Missing.Value;
Excel.Application excel = new Excel.Application();
Excel.Workbook workbook = excel.Workbooks.Add(missing);
int k = 0;
int tableCount = 6;
for (int j = 0; j < tableCount; j++)
{
Excel.Worksheet newWorksheet;
newWorksheet = (Excel.Worksheet)excel.Worksheets.Add(missing, missing, missing, missing);
System.Data.DataTable dt = new System.Data.DataTable();
dt = ds.Tables[j];
// name sheet
string tableName = string.Empty;
switch (j)
{
case 0:
tableName = "TEST1";
break;
case 1:
tableName = "TEST2";
break;
case 2:
tableName = "TEST3";
break;
case 3:
tableName = "TEST4";
break;
case 4:
tableName = "TEST5";
break;
case 5:
tableName = "TEST6";
break;
default:
tableName = "INVALID";
break;
}
newWorksheet.Name = tableName;
int iCol = 0;
foreach (DataColumn c in dt.Columns)
{
iCol++;
excel.Cells[1, iCol] = c.ColumnName;
}
int iRow = 0 + k;
foreach (DataRow r in dt.Rows)
{
iRow++;
for (int i = 1; i < dt.Columns.Count + 1; i++)
{
if (iRow == 1)
{
// Add the header the first time through
excel.Cells[iRow, i] = dt.Columns[i - 1].ColumnName;
}
if (r[1].ToString() != "")
{
excel.Cells[iRow + 1, i] = r[i - 1].ToString() + " - " + dt.Columns.Count;
}
}
}
k++;
}
return excel;
}

I think it's your int k variable and iRow that are the problems.
You set
int k = 0;
outside your looping through the tables.
Then inside the loop you have
int iRow = 0 + k;
and then you increment k at the end of the loop.
So for the first table you've got iRow = 0; second table, iRow = 1; third table, iRow = 2.

Related

Query Excel where Rows and Columns are reversed

How can I query an Excel file where the rows and columns are reversed / rotated 90 degrees?
Can it be done with a SELECT query, or do I need to recurse the cells programmatically?
It's for a .NET app, so linq or other suggestions are welcome.
Transpose a Datatable with a code like this:
private DataTable GenerateTransposedTable(DataTable inputTable)
{
DataTable outputTable = new DataTable(inputTable.TableName);
outputTable.Columns.Add(inputTable.Columns[0].ColumnName);
foreach (DataRow inRow in inputTable.Rows)
{
string newColName = inRow[0].ToString();
outputTable.Columns.Add(newColName);
}
for (int rCount = 1; rCount <= inputTable.Columns.Count - 1; rCount++)
{
DataRow newRow = outputTable.NewRow();
newRow[0] = inputTable.Columns[rCount].ColumnName;
for (int cCount = 0; cCount <= inputTable.Rows.Count - 1; cCount++)
{
string colValue = inputTable.Rows[cCount][rCount].ToString();
newRow[cCount + 1] = colValue;
}
outputTable.Rows.Add(newRow);
}
return outputTable;
}
.NET does not include a method to transpose data tables. You have to make your own. This website Link has a tutorial on an example transpose method. I will copy and paste the code snippet below:
private DataTable Transpose(DataTable dt)
{
DataTable dtNew = new DataTable();
//adding columns
for(int i=0; i<=dt.Rows.Count; i++)
{
dtNew.Columns.Add(i.ToString());
}
//Changing Column Captions:
dtNew.Columns[0].ColumnName = " ";
for(int i=0; i<dt.Rows.Count; i++)
{
//For dateTime columns use like below
dtNew.Columns[i+1].ColumnName =Convert.ToDateTime(dt.Rows[i].ItemArray[0].ToString()).ToString("MM/dd/yyyy");
//Else just assign the ItermArry[0] to the columnName prooperty
}
//Adding Row Data
for(int k=1; k<dt.Columns.Count; k++)
{
DataRow r = dtNew.NewRow();
r[0] = dt.Columns[k].ToString();
for(int j=1; j<=dt.Rows.Count; j++)
r[j] = dt.Rows[j-1][k];
dtNew.Rows.Add(r);
}
return dtNew;
}

Create Excel Sheet From a DataTable

I am facing a strange phenomenon.
I wrote a method that copy values from datatable to an excel sheet.
The problem is that the rows are copied to columns and columns to rows.
For example:
DataTable:
Item Quantity UnitPrice TotalPrice
A 10 2 20
B 3 15 45
C 100 0.5 50
Excel Sheet:
Item Quantity UnitPrice TotalPrice
A B C
10 3 100
2 15 0.5
20 45 50
My code:
private void PopulateDataWorkSheet()
{
xl.Workbooks xlWorkbooks = _xlApp.Workbooks;
xl.Workbook xlWorkbook = xlWorkbooks.Open(_excelFileName);
xl.Sheets xlSheets = xlWorkbook.Sheets;
const int startRowIndex = 2; // first row for columns title
const int startColumnIndex = 1;
xl.Worksheet xlDataWorkSheet = xlSheets[DATA_SHEET];
xl.Range xlCells = xlDataWorkSheet.Cells;
for (var rowindex = 0; rowindex < _datatable.Rows.Count; rowindex++)
{
for (var columnindex = 0; columnindex < _datatable.Columns.Count; columnindex++)
{
xlCells[startRowIndex + rowindex][startColumnIndex + columnindex] = _datatable.Rows[rowindex][columnindex];
}
}
xlWorkbook.Save();
xlWorkbook.Close();
xlWorkbooks.Close();
ReleaseExcelObject(xlCells);
ReleaseExcelObject(xlDataWorkSheet);
ReleaseExcelObject(xlSheets);
ReleaseExcelObject(xlWorkbook);
ReleaseExcelObject(xlWorkbooks);
}
I can simply solve it by changing as following but I am not clear what is wrong:
xlCells[startColumnIndex + columnindex][startRowIndex + rowindex] = _datatable.Rows[rowindex][columnindex];
Did I miss something in my code?
I am facing a strange phenomenon. Did I miss something in my code?
Welcome to the world of Excel Range, dynamics, optional parameters and COM object Default member concept.
Excel Range is a strange thing. Almost every method/property returns another range. The indexer you used is something like this
dynamic this[object RowIndex, object ColumnIndex = Type.Missing] { get; set; }
i.e. has required row index and optional column index.
Let take this call
xlCells[startRowIndex + rowindex][startColumnIndex + columnindex] = ...;
it's equivalent to something like this
var range1 = (Excel.Range)xlCells[startRowIndex + rowindex];
var range2 = (Excel.Range)range1[startColumnIndex + columnindex];
// ^^^^^^
// this is treated as row index offset from the range1
range2.Value2 = ...;
Shortly, you need to change it to
xlCells[startRowIndex + rowindex, startColumnIndex + columnindex] = ...;
You need to change how you access your excel cells.
cells[StartRowIndex+ rowindex, StartColumnIndex + columnindex] is Row first and then column. What you do is cells[StartRowIndex + rowindex][StartColumnIndex + columnindex] which takes the column as a first argument.
The order of the loops does not matter at all.. so the right solution would be:
for (var rowindex = 0; rowindex < _datatable.Rows.Count; rowindex++)
{
for (var columnindex = 0; columnindex < _datatable.Columns.Count; columnindex++)
{
xlCells[startRowIndex + rowindex, startColumnIndex + columnindex] = _datatable.Rows[rowindex][columnindex];
}
}
Cheers!
You doing it wrong, you need to go like this:
for (var columnindex = 0; columnindex < _datatable.Columns.Count; columnindex++)
{
for (var rowindex = 0; rowindex < _datatable.Rows.Count; rowindex++)
{
xlCells[startRowIndex + rowindex][startColumnIndex + columnindex] = _datatable.Rows[rowindex][columnindex];
}
}
you need the column and then the row.
You can use following code to overcome the problem.It works fine for me.
xlApplication = new Microsoft.Office.Interop.Excel.Application();
// Create workbook .
xlWorkBook = xlApplication.Workbooks.Add(Type.Missing);
// Get active sheet from workbook
xlWorkSheet = xlWorkBook.ActiveSheet;
xlWorkSheet.Name = "Report";
xlWorkSheet.Columns.ColumnWidth = 30;
xlApplication.DisplayAlerts = false;
for (int rowIndex = 0; rowIndex < gridViewDataTable.Rows.Count; rowIndex++)
{
for (int colIndex = 0; colIndex < gridViewDataTable.Columns.Count; colIndex++)
{
if (rowIndex == 0)
{
xlWorkSheet.Cells[rowIndex + 1, colIndex + 1] = gridViewDataTable.Columns[colIndex].ColumnName;
xlWorkSheet.Cells[rowIndex + 1, colIndex + 1].Interior.Color = System.Drawing.Color.LightGray;
}
xlWorkSheet.Cells[rowIndex + 2, colIndex + 1].Borders.Color = Color.Black;
xlWorkSheet.Cells[rowIndex + 2, colIndex + 1].Interior.Color = System.Drawing.Color.White;
xlWorkSheet.Cells[rowIndex + 2, colIndex + 1] = gridViewDataTable.Rows[rowIndex][colIndex];
}
}
xlWorkBook.SaveAs(filename);
xlWorkBook.Close();
xlApplication.Quit();

Is it possible to copy row (with data, merging, style) in Excel using Epplus?

The problem is that I need to insert data into Excel from the collection several times using a single template for the entire collection.
using (var pckg = new ExcelPackage(new FileInfo(association.TemplatePath)))
{
var workSheet = pckg.Workbook.Worksheets[1];
var dataTable = WorksheetToDataTable(workSheet);
/*Some stuff*/
FindAndReplaceValue(workSheet, dictionary, row);
}
private DataTable WorksheetToDataTable(ExcelWorksheet oSheet)
{
int totalRows = oSheet.Dimension.End.Row;
int totalCols = oSheet.Dimension.End.Column;
DataTable dt = new DataTable(oSheet.Name);
DataRow dr = null;
for (int i = 1; i <= totalRows; i++)
{
if (i > 1) dr = dt.Rows.Add();
for (int j = 1; j <= totalCols; j++)
{
if (i == 1)
dt.Columns.Add((oSheet.Cells[i, j].Value ?? "").ToString());
else
dr[j - 1] = (oSheet.Cells[i, j].Value ?? "").ToString();
}
}
return dt;
}
First picture - My template. Second - First element of collection (with data, style, merging). Third - Other elements has only data
I just made copies of rows
for (int i = 0; i < invoiceList.Count; i++)
{
workSheet.Cells[1, 1, totalRows, totalCols].Copy(workSheet.Cells[i * totalRows + 1, 1]);
}
If you want to copy range just use :
workSheet.Cells["A1:I1"].Copy(workSheet.Cells["A4:I4"]);

First column in Excel should continuously repeated in datagrid

I have an Excel file with 2 columns [file in my pc]? Now iam getting 2 columns with 8 rows with below code.but continuously i should get 5*2=10 more of same columns with 8 rows in datagridview.
I have written the code which gives result only 2 columns but I should get 10 more columns with 8 rows.below is my code
for (int Cnum = 1; Cnum <= ShtRange.Columns.Count; Cnum++)
{
dt.Columns.Add((ShtRange.Cells[1, Cnum] as Excel.Range).Value2.ToString());
}
for (int Rnum = 2; Rnum <= 9; Rnum++)
{
dt.Rows.Add((ShtRange.Cells[Rnum, 1] as Excel.Range).Value2.ToString(),
(ShtRange.Cells[Rnum, 1] as Excel.Range).Value2.ToString());
}
}
for (int i = 0; i < 13; i++)
{
DataGridViewTextBoxCell txtbx = new DataGridViewTextBoxCell();
DataGridViewColumn txcol = new DataGridViewColumn();
txcol.CellTemplate = txtbx;
txcol.HeaderText = "column" + i.ToString();
dg1.Columns.Add(txcol);
}
dg1.Rows.Add(8);
int dgRw, dgCol;
dgRw = dgCol = 0;
foreach (DataRow dr in dt.Rows)
{
dg1[dgCol, dgRw].Value = dr[0].ToString();
dgRw++;
if (dgRw == 8)
{
dgCol++;
dgRw = 0;
}

Remove column in datatable

I am exporting a datatable to an excel sheet successfully... In that excel sheet i have to display the columns(customerid,Productname,referenceno) of the data table except the last column.... now how can i display the data table in excel without display the last column(referenceno)...
anyone tell me the solution of this problem..
Thanks in Advance..
here is my code for export datatable to excel:
System.Data.DataTable dt = clsobj.convert_datagrid_orderlist_to_datatable(dvgorderlist, txtreferenceno);
oxl = new Excel.Application();
oxl.Visible = true;
oxl.DisplayAlerts = false;
wbook = oxl.Workbooks.Add(XlWBATemplate.xlWBATWorksheet);
oxl.ActiveCell.set_Item(2, 4, "Alfa Aesar");
wsheet = (Excel.Worksheet)wbook.ActiveSheet;
wsheet.Name = "Customers";
Excel.Range range = wsheet.get_Range("A6", "H6");
wsheet.get_Range("A6", "H6").Font.Name = "Times new Roman";
wsheet.get_Range("A6", "H6").Font.Size = 12;
wsheet.get_Range("A6", "H6").Interior.Color = ConvertColour(Color.SkyBlue);
oxl.ActiveWindow.DisplayGridlines = false;
int rowCount = 5;
foreach (DataRow dr in dt.Rows)
{
rowCount += 1;
for (int i = 1; i < dt.Columns.Count + 1; i++)
{
// Add the header the first time through
if (rowCount == 7)
{
wsheet.Cells[6, i] = dt.Columns[i - 1].ColumnName;
}
wsheet.Cells[rowCount, i] = dr[i - 1].ToString();
Excel.Range cellRange = (Range)wsheet.Cells[rowCount, i];
//cellRange.Interior.Color = 200;
//cellRange.Interior.Color = ConvertColour(Color.LightBlue);
cellRange.Cells.Borders.LineStyle = BorderStyle.FixedSingle;
}
}
cells = wsheet.get_Range(wsheet.Cells[2, 2],
wsheet.Cells[rowCount, dt.Columns.Count]);
cells.EntireColumn.AutoFit();
wsheet = null;
cells = null;
In your for statement change this line
for (int i = 1; i < dt.Columns.Count + 1; i++)
with this one
var filteredColumns = dt.Columns.OfType<DataColumn>()
.Where( x=> x.ColumnName != "referenceno" );
foreach (var column in filteredColumns )
{
//do whatever you want
//if you need the index you can create counter and increase it by 1 each loop
}
don't forget to use linq
using System.Linq ;
Did you try
dt.Columns.Remove[dt.Columns.Count - 1];
foreach (DataColumn dc in dt.Columns)
{
bool deleteIt = true;
foreach (StringDictionary sd in sdArray)
{
if (dc.ColumnName.Equals(sd["Name"]))
deleteIt = false;
}
if (deleteIt)
data.Columns.Remove(dc);
}
sdArray contains all the columns you want in your Excel worksheet. If you prefer you could use a normal string[] instead. I used an array of StringDictionaries because I have more information per row, such as width.
Linq is also very awesome to use for this kinds of tasks, but the example above only supports one row. So I figured we needed some diversity.
Try Worksheet.get_Range("rangeVal", "rangeVal").EntireColumn.Hidden = true;
dt.Columns.Remove[ColumnIndex];
Or
dt.Columns.Remove["ColumnName"];
try any ...

Categories

Resources