I want to read a selected cell range of Excel sheet into a DataTable without using OLEDB. And I don't want to use 3rd party tools either.
Here is what I have done so far:
public void converter()
{
xlApp = new Microsoft.Office.Interop.Excel.Application();
xlWorkbook = xlApp.Workbooks.Open(path);
Microsoft.Office.Interop.Excel.Sheets sheets = xlWorkbook.Worksheets;
xlWorksheet = xlWorkbook.Sheets[3];
for (int i = 1; i <= 10; i++)
{
range = xlWorksheet.get_Range("A2", "I8");
System.Array myvalues = (System.Array)range.Cells.Value;
//string[] strArray = ConvertToStringArray(myvalues);
//List<string> lst = myvalues.OfType<string>().ToList();
}
}
How can I achieve this?
After Googling, I ended up with following but I do not know how to make it work with cell range
public System.Data.DataTable READExcel(string path)
{
Microsoft.Office.Interop.Excel.Application objXL = null;
Microsoft.Office.Interop.Excel.Workbook objWB = null;
objXL = new Microsoft.Office.Interop.Excel.Application();
objWB = objXL.Workbooks.Open(path);
Microsoft.Office.Interop.Excel.Worksheet objSHT = objWB.Worksheets[5];
int rows = objSHT.UsedRange.Rows.Count;
int cols = objSHT.UsedRange.Columns.Count;
System.Data.DataTable dt = new System.Data.DataTable();
int noofrow = 1;
for (int c = 1; c <= cols; c++)
{
string colname = objSHT.Cells[1, c].Text;
dt.Columns.Add(colname);
noofrow = 2;
}
for (int r = noofrow; r <= rows; r++)
{
DataRow dr = dt.NewRow();
for (int c = 1; c <= cols; c++)
{
dr[c - 1] = objSHT.Cells[r, c].Text;
}
dt.Rows.Add(dr);
}
objWB.Close();
objXL.Quit();
return dt;
}
Kindly help me achieve this.
It's not perfect and you might need to tweek some parameters, I didn't check if it gets the correct area, thats your work.
But it gets a DataTable out of an Excel Worksheet, as you asked.
I'd prefer creating an custom object list with the columns as properties, rather than a DataTable, but thats only me.
public System.Data.DataTable READExcel(string path,int row,int col, int rowamount, int colamount, int worksheetindex)
{
Microsoft.Office.Interop.Excel.Application objXL = null;
Microsoft.Office.Interop.Excel.Workbook objWB = null;
objXL = new Microsoft.Office.Interop.Excel.Application();
objWB = objXL.Workbooks.Open(path);
Microsoft.Office.Interop.Excel.Worksheet objSHT = objWB.Worksheets[worksheetindex];
int rows = objSHT.UsedRange.Rows.Count;
int cols = objSHT.UsedRange.Columns.Count;
System.Data.DataTable dt = new System.Data.DataTable();
// Change that for other column names
for (int c = col; c <= col + colamount; c++)
{
dt.Columns.Add(objSHT.Cells[row, c].Text);
}
// read the content
for (int r = row; r <= row+rowamount; r++)
{
DataRow dr = dt.NewRow();
for (int c = col; c <= col+colamount; c++)
{
dr[c - 1] = objSHT.Cells[r, c].Text;
}
dt.Rows.Add(dr);
}
objWB.Close();
objXL.Quit();
return dt;
}
Call it like that:
// A2 -> row:2,col:1 till F6 row:2+4, col1+5
READExcel(#"path", 2, 1, 4, 5, 3);
The faster way would be using Value2, example: var range = xlWorksheet.Range["A3", "B4"].Value2; (get_Range() doesn't work with my excel)
and iterate over it, filling the DataTable. range[1,1] would be the content of A3 in this example.
Related
I'm loading excel sheet into a data grid view and making some processes on it but the data most be ordered in special way .
I'm looking for a way to order the column using combo box that shows all column header to allow user to order data right way
thanks
For using combobox to display column headers and sort column headers, you could try the following code.
public DataTable READExcel(string path)
{
Microsoft.Office.Interop.Excel.Application objXL = null;
Microsoft.Office.Interop.Excel.Workbook objWB = null;
objXL = new Microsoft.Office.Interop.Excel.Application();
objWB = objXL.Workbooks.Open(path);
Microsoft.Office.Interop.Excel.Worksheet objSHT = objWB.Worksheets[1];
int rows = objSHT.UsedRange.Rows.Count;
int cols = objSHT.UsedRange.Columns.Count;
DataTable dt = new DataTable();
int noofrow = 1;
for (int c = 1; c <= cols; c++)
{
string colname = objSHT.Cells[1, c].Text;
dt.Columns.Add(colname);
noofrow = 2;
}
for (int r = noofrow; r <= rows; r++)
{
DataRow dr = dt.NewRow();
for (int c = 1; c <= cols; c++)
{
dr[c - 1] = objSHT.Cells[r, c].Text;
}
dt.Rows.Add(dr);
}
objWB.Close();
objXL.Quit();
return dt;
}
private void Form1_Load(object sender, EventArgs e)
{
DataTable table = READExcel(#"C:\\...\\product.xlsx");
dataGridView1.DataSource = table;
for (int i = 0; i < dataGridView1.Columns.Count; i++)
{
comboBox1.Items.Add(dataGridView1.Columns[i].Name);
}
comboBox1.Sorted = true;
}
The result:
i am generating an Excel from DataSet using the following code
int ColumnsCount;
if (DataTable == null || (ColumnsCount = DataTable.Columns.Count) == 0)
throw new Exception("ExportToExcel: Null or empty input table!\n");
// load excel, and create a new workbook
Microsoft.Office.Interop.Excel.Application Excel = new Microsoft.Office.Interop.Excel.Application();
Excel.Workbooks.Add();
// single worksheet
Microsoft.Office.Interop.Excel._Worksheet Worksheet = Excel.ActiveSheet;
object[] Header = new object[ColumnsCount];
// column headings
for (int i = 0; i < ColumnsCount; i++)
Header[i] = DataTable.Columns[i].ColumnName;
Microsoft.Office.Interop.Excel.Range HeaderRange = Worksheet.get_Range((Microsoft.Office.Interop.Excel.Range)(Worksheet.Cells[1, 1]), (Microsoft.Office.Interop.Excel.Range)(Worksheet.Cells[1, ColumnsCount]));
HeaderRange.Value = Header;
HeaderRange.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.BlanchedAlmond); //ConsoleColor.Yellow;//
HeaderRange.Font.Bold = true;
// DataCells
int RowsCount = DataTable.Rows.Count;
object[,] Cells = new object[RowsCount, ColumnsCount];
for (int j = 0; j < RowsCount; j++)
for (int i = 0; i < ColumnsCount; i++)
Cells[j, i] = (DataTable.Rows[j][i]);
Worksheet.get_Range((Microsoft.Office.Interop.Excel.Range)(Worksheet.Cells[2, 1]), (Microsoft.Office.Interop.Excel.Range)(Worksheet.Cells[RowsCount + 1, ColumnsCount])).Value = Cells;
Worksheet.Columns.AutoFit();
Worksheet.SaveAs(ExcelFilePath);
Excel.Quit();
Console.Write("Excel file saved!");
However one of my columns is being shown as 1.004E+12 instead of 1004000003451, although it a string column being returned from sql server as varchar. How can i prevent it? Can any one help?
In the end it was simple, just used .columns method
Worksheet.Columns("A").NumberFormat ="#";
I'm begining in WPF and i'm working with datagrid
I have multi datagrids. If i click a button ("Export" button) first time, it will create a new excel window and export data to first sheet. Then, i change to another datagrid and click a button ("Export" button) second time. so, it will create a new sheet in excel window which created before. Can you help me change my code ?
Thank you very much!!
public void Export(DataTable dt, string sheetName, string title)
{
Microsoft.Office.Interop.Excel.Application oExcel = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbooks oBooks;
Microsoft.Office.Interop.Excel.Sheets oSheets;
Microsoft.Office.Interop.Excel.Workbook oBook;
Microsoft.Office.Interop.Excel.Worksheet oSheet;
Excel.Range _range = null;
oExcel.DisplayAlerts = false;
oExcel.Application.SheetsInNewWorkbook = 1;
oBooks = oExcel.Workbooks;
oBook = (Microsoft.Office.Interop.Excel.Workbook)(oExcel.Workbooks.Add(Type.Missing));
oSheets = oBook.Worksheets;
oSheet = (Microsoft.Office.Interop.Excel.Worksheet)oSheets.get_Item(1);
oSheet.Name = sheetName;
Microsoft.Office.Interop.Excel.Range head = oSheet.get_Range("A1", "C1");
head.MergeCells = true;
head.Value2 = title;
head.Font.Bold = true;
head.Font.Name = "Tahoma";
head.Font.Size = "18";
head.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter;
List<object> objHeaders = new List<object>();
for (int n = 0; n <= dt.Rows.Count; n++)
{
objHeaders.Add(dt.Columns[n].ColumnName);
}
var headerToAdd = objHeaders.ToArray();
_range = oSheet.get_Range("A3", Type.Missing);
_range = _range.get_Resize(dt.Rows.Count, dt.Columns.Count);
_range.ColumnWidth = 30;
_range.set_Value(Type.Missing, headerToAdd);
Excel.Range rowHead = oSheet.get_Range("A3", "C"+dt.Columns.Count);
rowHead.Font.Bold = true;
rowHead.Borders.LineStyle = Microsoft.Office.Interop.Excel.Constants.xlSolid;
rowHead.Interior.ColorIndex = 15;
rowHead.HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter;
int row = dt.Rows.Count;
int col = dt.Columns.Count;
object[,] arr = new object[row, col];
for (int r = 0; r < dt.Rows.Count; r++)
{
DataRow dr = dt.Rows[r];
for (int c = 0; c < dt.Columns.Count; c++)
{
arr[r, c] = dr[c];
}
}
int rowStart = 4;
int columnStart = 1;
int rowEnd = rowStart + dt.Rows.Count - 1;
int columnEnd = dt.Columns.Count;
Microsoft.Office.Interop.Excel.Range c1 = (Microsoft.Office.Interop.Excel.Range)oSheet.Cells[rowStart, columnStart];
Microsoft.Office.Interop.Excel.Range c2 = (Microsoft.Office.Interop.Excel.Range)oSheet.Cells[rowEnd, columnEnd];
Microsoft.Office.Interop.Excel.Range range = oSheet.get_Range(c1, c2);
range.Value2 = arr;
range.Borders.LineStyle = Microsoft.Office.Interop.Excel.Constants.xlSolid;
Microsoft.Office.Interop.Excel.Range c3 = (Microsoft.Office.Interop.Excel.Range)oSheet.Cells[rowEnd, columnStart];
Microsoft.Office.Interop.Excel.Range c4 = oSheet.get_Range(c1, c3);
oSheet.get_Range(c3, c4).HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter;
oExcel.Visible = true;
}
}
You need to use field Microsoft.Office.Interop.Excel.Application oExcel in your class to store its value. First time it will be null, but on second - it will be opened excel. But you must be carefull with such a behavior, user can close excel, before 2nd export. So you need implement Closed event handler and clear your field (similar problem)
So, after much researching and using code below in a Class the items I'm passing (a DataTable) open up in Excel. I have around 5 sheets that need to open in the same book. The code below is for the first 2. The problem is they are all opening in NEW WorkBooks -- I need them all to open in the SAME WorkBook. They are opening on the correct sheet in each new Workbook though. I thought a simple "if" statement would work, however, it is not--
Any input on how to get them consolidated into one WorkBook would be greatly appreciated and thanks in advance!
Microsoft.Office.Interop.Excel.Application oExcel = new
Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbooks oBooks;
Microsoft.Office.Interop.Excel.Sheets oSheets;
Microsoft.Office.Interop.Excel.Workbook oBook;
Microsoft.Office.Interop.Excel.Worksheet oSheet;
oExcel.Visible = true;
oExcel.DisplayAlerts = false;
oExcel.Application.SheetsInNewWorkbook = 5;
oBooks = oExcel.Workbooks;
oBook = (Microsoft.Office.Interop.Excel.Workbook)(oExcel.Workbooks.Add(Type.Missing));
oSheets = oBook.Worksheets;
if (sheetName == "Combined")
{
oSheet = (Microsoft.Office.Interop.Excel.Worksheet)oSheets.get_Item(1);
oSheet.Name = sheetName;
object[,] arr = new object[dt.Rows.Count, dt.Columns.Count];
for (int r = 0; r < dt.Rows.Count; r++)
{
DataRow dr = dt.Rows[r];
for (int c = 0; c < dt.Columns.Count; c++)
{
arr[r, c] = dr[c];
}
}
Microsoft.Office.Interop.Excel.Range c1 = (Microsoft.Office.Interop.Excel.Range)oSheet.Cells[1, 1];
Microsoft.Office.Interop.Excel.Range c2 = (Microsoft.Office.Interop.Excel.Range)oSheet.Cells[1 + dt.Rows.Count - 1, dt.Columns.Count];
Microsoft.Office.Interop.Excel.Range range = oSheet.get_Range(c1, c2);
range.Value2 = arr;
}
else if (sheetName == "Auto")
{
oSheet = (Microsoft.Office.Interop.Excel.Worksheet)oSheets.get_Item(2);
oSheet.Name = sheetName;
object[,] arr = new object[dt.Rows.Count, dt.Columns.Count];
for (int r = 0; r < dt.Rows.Count; r++)
{
DataRow dr = dt.Rows[r];
for (int c = 0; c < dt.Columns.Count; c++)
{
arr[r, c] = dr[c];
}
}
Microsoft.Office.Interop.Excel.Range c1 =
(Microsoft.Office.Interop.Excel.Range)oSheet.Cells[1, 1];
Microsoft.Office.Interop.Excel.Range c2 =
(Microsoft.Office.Interop.Excel.Range)oSheet.Cells[1 + dt.Rows.Count - 1,
dt.Columns.Count];
Microsoft.Office.Interop.Excel.Range range = oSheet.get_Range(c1, c2);
range.Value2 = arr;
}
Well your code is a bit too long to understand without comments, but if you wanna add a new sheet inside your current workbook, there is the myWorkbook.Sheets.Add() method (where myWorkbook is a ref to your current workbook).
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.sheets.add(v=office.14).aspx
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 ...