Issue regarding line chart generation from datatable to excel c# - c#

i am using Interop.Excel to export data from datatable and generate line chart too. i have got a code which export data to excel from data table and also create chart there but the code is giving error at this line
Excel.Axis yAxis = (Excel.Axis)xlChart.Axes(Excel.XlAxisType.xlSeriesAxis,
Excel.XlAxisGroup.xlPrimary);
and the error message i am getting Value does not fall within the expected range
my full code for line chart generation.
private void button1_Click(object sender, EventArgs e)
{
System.Data.DataTable dt = GetGraphData();
Excel.Application xla = new Excel.Application();
xla.Visible = true;
Excel.Workbook wb = xla.Workbooks.Add(Excel.XlSheetType.xlWorksheet);
Excel.Worksheet ws = (Excel.Worksheet)wb.ActiveSheet;
//********************** Now create the chart. *****************************
Excel.ChartObjects chartObjs = (Excel.ChartObjects)ws.ChartObjects(Type.Missing);
Excel.ChartObject chartObj = chartObjs.Add(250, 60, 300, 300);
Excel.Chart xlChart = chartObj.Chart;
int nRows = 2;
int nColumns = dt.Rows.Count;
string upperLeftCell = "B2";
int endRowNumber = System.Int32.Parse(upperLeftCell.Substring(1))
+ nRows - 1;
char endColumnLetter = System.Convert.ToChar(
Convert.ToInt32(upperLeftCell[0]) + nColumns - 1);
string upperRightCell = System.String.Format("{0}{1}",
endColumnLetter, System.Int32.Parse(upperLeftCell.Substring(1)));
string lowerRightCell = System.String.Format("{0}{1}",
endColumnLetter, endRowNumber);
Excel.Range rg = ws.get_Range(upperLeftCell, lowerRightCell);
for (int i = 1; i <= dt.Rows.Count; i++)
{
rg[1, i] = dt.Rows[i - 1][0].ToString(); //For Adding Header Text
rg[2, i] = int.Parse(dt.Rows[i - 1][1].ToString()); //For Adding Datarow Value
}
Excel.Range chartRange = ws.get_Range(upperLeftCell, lowerRightCell);
xlChart.SetSourceData(chartRange, Type.Missing);
xlChart.ChartType = Excel.XlChartType.xlLine;
// *******************Customize axes: ***********************
Excel.Axis xAxis = (Excel.Axis)xlChart.Axes(Excel.XlAxisType.xlCategory,
Excel.XlAxisGroup.xlPrimary);
//xAxis.HasTitle = true;
// xAxis.AxisTitle.Text = "X Axis";
Excel.Axis yAxis = (Excel.Axis)xlChart.Axes(Excel.XlAxisType.xlSeriesAxis,
Excel.XlAxisGroup.xlPrimary);
//yAxis.HasTitle = true;
//yAxis.AxisTitle.Text = "Y Axis";
Excel.Axis zAxis = (Excel.Axis)xlChart.Axes(Excel.XlAxisType.xlValue,
Excel.XlAxisGroup.xlPrimary);
//zAxis.HasTitle = true;
//zAxis.AxisTitle.Text = "Z Axis";
// *********************Add title: *******************************
xlChart.HasTitle = true;
xlChart.ChartTitle.Text = "Project Status Graph";
// *****************Set legend:***************************
xlChart.HasLegend = true;
FileStream file = new FileStream(#"c:\pop.xls", FileMode.Create);
file.Close();
wb.SaveCopyAs(#"c:\pop.xls");
// ****************For Quiting The Excel Aplication ***********************
if (xla != null)
{
xla.DisplayAlerts = false;
wb.Close();
wb = null;
xla.Quit();
xla = null;
}
}
private System.Data.DataTable GetGraphData()
{
System.Data.DataTable dt = new System.Data.DataTable();
dt.Columns.AddRange(new DataColumn[2] { new DataColumn("ProjectStatus"), new DataColumn("per") });
DataRow dr1 = dt.NewRow();
dr1[0] = "Compleet";
dr1[1] = 20;
dt.Rows.Add(dr1);
DataRow dr2 = dt.NewRow();
dr2[0] = "Pending";
dr2[1] = 20;
dt.Rows.Add(dr2);
DataRow dr3 = dt.NewRow();
dr3[0] = "UnCompleet";
dr3[1] = 20;
dt.Rows.Add(dr3);
return dt;
}
looking for help. thanks

My coworker tells me that according to intellisense, the value of the first argument (Excel.XlAxisType.xlSeriesAxis) is valid only for 3D charts.
What kind of chart are you creating?

Related

How would I save and load a datagridview c#?

I have a datagridview and already have a export function using Microsoft interop however i am struggling to find a solution to the loading the data.
My code to export to Excel:
private void iSave()
{
Microsoft.Office.Interop.Excel._Application app = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel._Workbook workbook = app.Workbooks.Add(Type.Missing);
Microsoft.Office.Interop.Excel._Worksheet worksheet = null;
app.Visible = true;
worksheet = workbook.Sheets["Journal"];
worksheet = workbook.ActiveSheet;
worksheet.Name = "Exported from Journal Pro";
for (int i = 1; i < dataGridView1.Columns.Count + 1; i++)
{
worksheet.Cells[1, i] = dataGridView1.Columns[i - 1].HeaderText;
}
for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
{
for (int j = 0; j < dataGridView1.Columns.Count; j++)
{
worksheet.Cells[i + 2, j + 1] = dataGridView1.Rows[i].Cells[j].Value.ToString();
}
}
}
I also want it to add data from the second row as the first row is the title of the columns.
If theres a solution to use excel to load data in using the same format which is exported in i would be grateful :)
I am also open to other methods of saving, it doesn't have to be to an excel file.
I have used some other codes found online such as
`
using (OpenFileDialog ofd = new OpenFileDialog())
{
ofd.Filter = "Excel Files Only | *.xlsx; *.xls";
ofd.Title = "Choose the File";
if (ofd.ShowDialog() == DialogResult.OK)
FileName_LBL.Text = ofd.FileName;
}
Microsoft.Office.Interop.Excel._Application xlapp;
Microsoft.Office.Interop.Excel._Workbook xlworkbook;
Microsoft.Office.Interop.Excel._Worksheet xlworksheet;
Microsoft.Office.Interop.Excel._Worksheet xlrange;
try
{
xlapp = new Microsoft.Office.Interop.Excel.Application();
xlworkbook = xlapp.Workbooks.Open(FileName_LBL.Text);
xlworksheet = xlworkbook.Worksheets["Exported from Journal Pro"];
xlrange = (Microsoft.Office.Interop.Excel._Worksheet)xlworksheet.UsedRange;
dataGridView1.ColumnCount = xlrange.Columns.Count;
for (int xlrow = 2; xlrow <= xlrange.Rows.Count; xlrow++)
{
dataGridView1.Rows.Add(xlrange.Cells[xlrow, 2].Text, xlrange.Cells[xlrow, 3].Text, xlrange.Cells[xlrow, 4].Text, xlrange.Cells[xlrow, 5].Text, xlrange.Cells[xlrow, 6].Text, xlrange.Cells[xlrow, 7].Text);
}
xlworkbook.Close();
xlapp.Quit();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
`
but i get errors such as DISP_E_BADINDEX and E_NOINTERFACE
You can use this method to finish loading the data.
Step 1: Convert dataGridView to dataTable.
Step 2: Export dataTable to Excel .
Step 3: button calls the OutputExcel method.
Full Code
private void button1_Click(object sender, EventArgs e)
{
OutputExcel(dataGridView1);
}
public void OutputExcel(DataGridView dataGridView)
{
string filePath = "";
SaveFileDialog s = new SaveFileDialog();
s.Title = "Excel";
s.Filter = "Excel(*.xlsx)|*.xlsx";
s.FilterIndex = 1;
if (s.ShowDialog() == DialogResult.OK)
filePath = s.FileName;
else
return;
//Step 1: Convert dataGridView to dataTable
DataTable tmpDataTable = new DataTable("tmpDataTable");
DataTable modelTable = new DataTable("ModelTable");
for (int column = 0; column < dataGridView.Columns.Count; column++)
{
if (dataGridView.Columns[column].Visible == true)
{
DataColumn tempColumn = new DataColumn(dataGridView.Columns[column].HeaderText, typeof(string));
tmpDataTable.Columns.Add(tempColumn);
DataColumn modelColumn = new DataColumn(dataGridView.Columns[column].Name, typeof(string));
modelTable.Columns.Add(modelColumn);
}
}
for (int row = 0; row < dataGridView.Rows.Count; row++)
{
if (dataGridView.Rows[row].Visible == false)
continue;
DataRow tempRow = tmpDataTable.NewRow();
for (int i = 0; i < tmpDataTable.Columns.Count; i++)
tempRow[i] = dataGridView.Rows[row].Cells[modelTable.Columns[i].ColumnName].Value;
tmpDataTable.Rows.Add(tempRow);
}
if (tmpDataTable == null)
{
return;
}
//Step 2: Export dataTable to Excel
long rowNum = tmpDataTable.Rows.Count;//line
int columnNum = tmpDataTable.Columns.Count;//column
Excel.Application m_xlApp = new Excel.Application();
m_xlApp.DisplayAlerts = false;
m_xlApp.Visible = false;
Excel.Workbooks workbooks = m_xlApp.Workbooks;
Excel.Workbook workbook = workbooks.Add(Excel.XlWBATemplate.xlWBATWorksheet);
Excel.Worksheet worksheet = (Excel.Worksheet)workbook.Worksheets[1];//Get sheet1
try
{
string[,] datas = new string[rowNum + 1, columnNum];
for (int i = 0; i < columnNum; i++) //Write field
datas[0, i] = tmpDataTable.Columns[i].Caption;
Excel.Range range = m_xlApp.Range[worksheet.Cells[1, 1], worksheet.Cells[1, columnNum]];
range.Interior.ColorIndex = 15;
range.Font.Bold = true;
range.Font.Size = 10;
int r = 0;
for (r = 0; r < rowNum; r++)
{
for (int i = 0; i < columnNum; i++)
{
object obj = tmpDataTable.Rows[r][tmpDataTable.Columns[i].ToString()];
datas[r + 1, i] = obj == null ? "" : "'" + obj.ToString().Trim();
}
Application.DoEvents();
}
Excel.Range fchR = m_xlApp.Range[worksheet.Cells[1, 1], worksheet.Cells[rowNum + 1, columnNum]];
fchR.Value2 = datas;
worksheet.Columns.EntireColumn.AutoFit();
m_xlApp.Visible = false;
range = m_xlApp.Range[worksheet.Cells[1, 1], worksheet.Cells[rowNum + 1, columnNum]];
range.Font.Size = 9;
range.RowHeight = 14.25;
range.Borders.LineStyle = 1;
range.HorizontalAlignment = 1;
workbook.Saved = true;
workbook.SaveCopyAs(filePath);
}
catch (Exception ex)
{
MessageBox.Show("Export Exception:" + ex.Message, "Export Exception", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
m_xlApp.Workbooks.Close();
m_xlApp.Workbooks.Application.Quit();
m_xlApp.Application.Quit();
m_xlApp.Quit();
MessageBox.Show("Export successful!", "Tips", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
Effect:
Hope it can help you.

Please suggest how to set userdefined colors to bar

How to set the user-defined color for series, not able to figure it out, Please help
private void button1_Click(object sender, EventArgs e) {
Microsoft.Office.Interop.Excel.Application excelWrite = new Microsoft.Office.Interop.Excel.Application();
// Create empty workbook
excelWrite.Workbooks.Add();
// Create Worksheet from active sheet
Microsoft.Office.Interop.Excel._Worksheet workSheet = excelWrite.ActiveSheet;
workSheet.Name = "Result";
workSheet.Cells[1, "A"] = "Color";
workSheet.Cells[2, "A"] = "R";
workSheet.Cells[3, "A"] = "G";
workSheet.Cells[4, "A"] = "B";
workSheet.Cells[1, "B"] = "Brown";
workSheet.Cells[1, "C"] = "Pink";
workSheet.Cells[1, "D"] = "Silver";
workSheet.Cells[2, "B"] = 40;
workSheet.Cells[3, "B"] = 26;
workSheet.Cells[4, "B"] = 13;
workSheet.Cells[2, "C"] = 100;
workSheet.Cells[3, "C"] = 75;
workSheet.Cells[4, "C"] = 80;
workSheet.Cells[2, "D"] = 75;
workSheet.Cells[3, "D"] = 75;
workSheet.Cells[4, "D"] = 75;
Microsoft.Office.Interop.Excel.Range xlRange = workSheet.UsedRange;
int rowCount = xlRange.Rows.Count;
int colCount = xlRange.Columns.Count;
Microsoft.Office.Interop.Excel.ChartObjects xlCharts = (Microsoft.Office.Interop.Excel.ChartObjects)workSheet.ChartObjects(Type.Missing);
Microsoft.Office.Interop.Excel.ChartObject myChart = (Microsoft.Office.Interop.Excel.ChartObject)xlCharts.Add(150, 150, 800, 350);
Microsoft.Office.Interop.Excel.Chart chartPage = myChart.Chart;
chartPage.SetSourceData(xlRange, Type.Missing);
chartPage.ChartType = Microsoft.Office.Interop.Excel.XlChartType.xlBarStacked100;
chartPage.AutoScaling = true;
Microsoft.Office.Interop.Excel.ChartClass cc = myChart.
excelWrite.DisplayAlerts = false;
workSheet.SaveAs(#"C:\Users\apex\Desktop\" + "Result_ForChart_" + DateTime.Now.ToString("yyyyMMdd") + ".xlsx");
ClearAllEndAll(excelWrite, workSheet);
Defeat();
}
Is it possible to do with interop, if not Please suggest other nuget/lib to be used
Have you tried EPPlus? It's an OOXML wrapper that allows you to create Excel spreadsheets with ease. It is available via NuGet or on github (https://github.com/JanKallman/EPPlus).
Edit - Here is a code sample:
using (FileStream stream = new FileStream("test.xlsx", FileMode.Create))
using (ExcelPackage package = new ExcelPackage())
{
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("My Data");
Color bgcolor = ColorTranslator.FromHtml("#00FFFF");
worksheet.Cells["A1:B1"].Style.Fill.PatternType = ExcelFillStyle.Solid;
worksheet.Cells["A1:B1"].Style.Fill.BackgroundColor.SetColor(bgcolor);
worksheet.Cells["A1"].Value = "Hello";
worksheet.Cells["B1"].Value = "World!";
package.SaveAs(stream);
}

Importing large .xlsx file very slow

I'm new to c# and WPF and trying to import a large .xlsx file into a datagrid, i can have around 200+ columns & 100,000+ rows. With my current method it is taking over an hour (i didn't let it finish). An example of my format in csv terms would be;
"Time","Dist","V_Front","V_Rear","RPM"
"s","m","km/h","km/h","rpm"
"0.000","0","30.3","30.0","11995"
"0.005","0","30.3","30.0","11965"
"0.010","0","30.3","31.0","11962"
I'm using Interop at the moment but i'm wondering whether there is another approach which would drastically cut down load time. I hope to plot this data using SciCharts (they have a student licence), with check boxes for channel selection but that's another matter.
.CS
private void Button_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openfile = new OpenFileDialog();
openfile.DefaultExt = ".xlsx";
openfile.Filter = "(.xlsx)|*.xlsx";
var browsefile = openfile.ShowDialog();
if (browsefile == true)
{
txtFilePath.Text = openfile.FileName;
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook excelBook = excelApp.Workbooks.Open(txtFilePath.Text.ToString(), 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
Microsoft.Office.Interop.Excel.Worksheet excelSheet = (Microsoft.Office.Interop.Excel.Worksheet)excelBook.Worksheets.get_Item(1); ;
Microsoft.Office.Interop.Excel.Range excelRange = excelSheet.UsedRange;
string strCellData = "";
double douCellData;
int rowCnt = 0;
int colCnt = 0;
DataTable dt = new DataTable();
for (colCnt = 1; colCnt <= excelRange.Columns.Count; colCnt++)
{
string strColumn = "";
strColumn = (string)(excelRange.Cells[1, colCnt] as Microsoft.Office.Interop.Excel.Range).Value2;
dt.Columns.Add(strColumn, typeof(string));
}
for (rowCnt = 2; rowCnt <= excelRange.Rows.Count; rowCnt++)
{
string strData = "";
for (colCnt = 1; colCnt <= excelRange.Columns.Count; colCnt++)
{
try
{
strCellData = (string)(excelRange.Cells[rowCnt, colCnt] as Microsoft.Office.Interop.Excel.Range).Value2;
strData += strCellData + "|";
}
catch (Exception ex)
{
douCellData = (excelRange.Cells[rowCnt, colCnt] as Microsoft.Office.Interop.Excel.Range).Value2;
strData += douCellData.ToString() + "|";
}
}
strData = strData.Remove(strData.Length - 1, 1);
dt.Rows.Add(strData.Split('|'));
}
dtGrid.ItemsSource = dt.DefaultView;
excelBook.Close(true, null, null);
excelApp.Quit();
}
}
Any help i really appreciated.
The problem is that there is too many individual reads which causes a lot of reflection usage and marshalling between Excel and your application. If you're not concerned about memory usage, you can just read the whole Range into memory and work from memory instead of individually reading cells. The below code runs in 3880 ms on a test file with 5 columns and 103938 rows:
OpenFileDialog openfile = new OpenFileDialog();
openfile.DefaultExt = ".xlsx";
openfile.Filter = "(.xlsx)|*.xlsx";
var browsefile = openfile.ShowDialog();
if (browsefile == true)
{
txtFilePath.Text = openfile.FileName;
var excelApp = new Microsoft.Office.Interop.Excel.Application();
var excelBook = excelApp.Workbooks.Open(txtFilePath.Text, 0, true, 5, "", "", true,
Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
var excelSheet = (Microsoft.Office.Interop.Excel.Worksheet) excelBook.Worksheets.Item[1];
Microsoft.Office.Interop.Excel.Range excelRange = excelSheet.UsedRange;
DataTable dt = new DataTable();
object[,] value = excelRange.Value;
int columnsCount = value.GetLength(1);
for (var colCnt = 1; colCnt <= columnsCount; colCnt++)
{
dt.Columns.Add((string)value[1, colCnt], typeof(string));
}
int rowsCount = value.GetLength(0);
for (var rowCnt = 2; rowCnt <= rowsCount; rowCnt++)
{
var dataRow = dt.NewRow();
for (var colCnt = 1; colCnt <= columnsCount; colCnt++)
{
dataRow[colCnt - 1] = value[rowCnt, colCnt];
}
dt.Rows.Add(dataRow);
}
dtGrid.ItemsSource = dt.DefaultView;
excelBook.Close(true);
excelApp.Quit();
}
If you don't want to read the whole Range in, then you should do that in sensible batches.
Another optimization is to run this on a background thread, so it won't block the UI while it's loading.
Edit
For running this on a background thread you could modify the button click handler to be an async method and put the parsing logic into another method which runs the actual parsing on a threadpool thread with Task.Run:
private async void Button_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openfile = new OpenFileDialog();
openfile.DefaultExt = ".xlsx";
openfile.Filter = "(.xlsx)|*.xlsx";
var browsefile = openfile.ShowDialog();
if (browsefile == true)
{
txtFilePath.Text = openfile.FileName;
DataTable dataTable = await ParseExcel(txtFilePath.Text).ConfigureAwait(true);
dtGrid.ItemsSource = dataTable.DefaultView;
}
}
private Task<DataTable> ParseExcel(string filePath)
{
return Task.Run(() =>
{
var excelApp = new Microsoft.Office.Interop.Excel.Application();
var excelBook = excelApp.Workbooks.Open(filePath, 0, true, 5, "", "", true,
Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
var excelSheet = (Microsoft.Office.Interop.Excel.Worksheet) excelBook.Worksheets.Item[1];
Microsoft.Office.Interop.Excel.Range excelRange = excelSheet.UsedRange;
DataTable dt = new DataTable();
object[,] value = excelRange.Value;
int columnsCount = value.GetLength(1);
for (var colCnt = 1; colCnt <= columnsCount; colCnt++)
{
dt.Columns.Add((string) value[1, colCnt], typeof(string));
}
int rowsCount = value.GetLength(0);
for (var rowCnt = 2; rowCnt <= rowsCount; rowCnt++)
{
var dataRow = dt.NewRow();
for (var colCnt = 1; colCnt <= columnsCount; colCnt++)
{
dataRow[colCnt - 1] = value[rowCnt, colCnt];
}
dt.Rows.Add(dataRow);
}
excelBook.Close(true);
excelApp.Quit();
return dt;
});
}
The handler just invokes the parsing function, the parsing function runs on a background thread and when it finishes the handler can continue by assigning the resulting DataTable to the ItemsSource.

Some data is missing in the Export to Excel using DataTable and Linq

I am exporting three worked sheet in single XL file, but I am missing some user data in the second DataTable (Education Details sheet) and third DataTable (Employeement Details sheet).
The Education Details sheet is some users are not there, but an Employeement Details sheet that users are showing. User Email Id's is there all three Database Tables.
DataSe ds = new DataSet();
DataTable dt = new DataTable("Registration Details");
DataTable dt1 = new DataTable("Education Details");
DataTable dt2 = new DataTable("Employeement Details");
dt = bl.Get_Registrationdetailsbydate(bo);
gv_Regdetails.DataSource = dt;
gv_Regdetails.DataBind();
dt1 = bl.Get_Registrationdetailsbydate1(bo);
dt2 = bl.Get_Registrationdetailsbydate2(bo);
DataTable filteredEducation = dt1.AsEnumerable()
.Where(x => dt.AsEnumerable()
.Any(z => z.Field<string>("Email").Trim() == x.Field<string>("Email").Trim()))
.CopyToDataTable();
DataTable filteredEmployee = dt2.AsEnumerable()
.Where(x => dt.AsEnumerable()
.Any(z => z.Field<string>("Email").Trim() == x.Field<string>("Email").Trim()))
.CopyToDataTable();
dt.TableName = "Registration Details";
filteredEducation.TableName = "Education Details";
filteredEmployee.TableName = "Employeement Details";
ds.Tables.Add(dt);
ds.Tables.Add(filteredEducation);
ds.Tables.Add(filteredEmployee);
ExcelHelper.ToExcel(ds, "DangoteUsers.xls", Page.Response);
I did result base on first DataTable users Email, then fill second DataTable detail users base on first DataTable Email id's. Same as Employment Details. The issue in first DataTable and second DataTable. I am not returning the DataTable also.
I refer this example
The problem is coming somewhere from the solution of conversion from DataSet to Excel in the article. Using this self made conversion is not a good idea. Use Jet/ACE engine or Microsoft Office Interop. At least they guarantee, they don't have such kind of bugs, which in future can became more. Better use something which is already highly accepted by the community. Here I wrote an approach how to do it with Interop.
First what you need to do is to add the reference to Microsoft.Office.Interop.Excel. Here is how to do it, taken from msdn article
Add the Excel assembly as a reference to the project: Right-click on
the project, select Add Reference.
Click the COM tab of the Add Reference dialog box, and find Microsoft
Excel 11 Object Library.
Double-click on Microsoft Excel 11 Object Library, and
press OK.
Obviously if you have bigger version of Excel 11 use it.
Here is the code, there are comments/regions with the workflow of it. You should use using Excel = Microsoft.Office.Interop.Excel; as reference
public void ExcelBtn_Click(object sender, EventArgs e)
{
DataSet dst = PrepareData();
byte[] bytes = ExportDataSetToExcel(dst);
Response.ClearContent();
Response.ContentType = "application/msoffice";
Response.AddHeader("Content-Disposition", #"attachment; filename=""ExportedExcel.xlsx"" ");
Response.BinaryWrite(bytes);
Response.End();
}
public static DataSet PrepareData()
{
DataTable badBoysDst = new DataTable("BadBoys");
badBoysDst.Columns.Add("Nr");
badBoysDst.Columns.Add("Name");
badBoysDst.Rows.Add(1, "Me");
badBoysDst.Rows.Add(2, "You");
badBoysDst.Rows.Add(3, "Pepe");
badBoysDst.Rows.Add(4, "Roni");
//Create a Department Table
DataTable goodBoysDst = new DataTable("GoodBoys");
goodBoysDst.Columns.Add("Nr");
goodBoysDst.Columns.Add("Name");
goodBoysDst.Rows.Add("1", "Not me");
goodBoysDst.Rows.Add("2", "Not you");
goodBoysDst.Rows.Add("3", "Quattro");
goodBoysDst.Rows.Add("4", "Stagioni");
DataTable goodBoysDst2 = new DataTable("GoodBoys2");
goodBoysDst2.Columns.Add("Nr");
goodBoysDst2.Columns.Add("Name");
goodBoysDst2.Rows.Add("1", "Not me");
goodBoysDst2.Rows.Add("2", "Not you");
goodBoysDst2.Rows.Add("3", "Quattro");
goodBoysDst2.Rows.Add("4", "Stagioni");
DataTable goodBoysDst3 = new DataTable("GoodBoys3");
goodBoysDst3.Columns.Add("Nr");
goodBoysDst3.Columns.Add("Name");
goodBoysDst3.Rows.Add("1", "Not me");
goodBoysDst3.Rows.Add("2", "Not you");
goodBoysDst3.Rows.Add("3", "Quattro");
goodBoysDst3.Rows.Add("4", "Stagioni");
//Create a DataSet with the existing DataTables
DataSet dst = new DataSet("SchoolBoys");
dst.Tables.Add(badBoysDst);
dst.Tables.Add(goodBoysDst);
dst.Tables.Add(goodBoysDst2);
dst.Tables.Add(goodBoysDst3);
return dst;
}
public static byte[] ExportDataSetToExcel(DataSet dst)
{
#region Create The Excel
Excel.Application excelApp = null;
Excel.Workbook excelWorkBook = null;
try
{
excelApp = new Excel.Application();
if (excelApp == null)
throw new Exception("You can throw custom exception here too");
excelWorkBook = excelApp.Workbooks.Add();
int sheetNr = 1;
foreach (DataTable table in dst.Tables)
{
Excel.Worksheet excelWorkSheet = null;
//Add a new worksheet or reuse first 3 sheets of workbook with the Datatable name
if (sheetNr <= excelWorkBook.Sheets.Count)
{
excelWorkSheet = excelWorkBook.Sheets.get_Item(sheetNr);
}
else
{
excelWorkSheet = excelWorkBook.Sheets.Add(After: excelWorkBook.Sheets[excelWorkBook.Sheets.Count]);
}
excelWorkSheet.Name = table.TableName;
for (int i = 1; i < table.Columns.Count + 1; i++)
{
excelWorkSheet.Cells[1, i] = table.Columns[i - 1].ColumnName;
}
for (int j = 0; j < table.Rows.Count; j++)
{
for (int k = 0; k < table.Columns.Count; k++)
{
excelWorkSheet.Cells[j + 2, k + 1] = table.Rows[j].ItemArray[k].ToString();
}
}
sheetNr += 1;
}
//make first sheet active
excelApp.ActiveWorkbook.Sheets[1].Select();
excelWorkBook.SaveAs(#"c:\temp\DataSetToExcel.xlsx");
}
finally
{
excelWorkBook.Close();
excelApp.Quit();
//you should call GC here because there is memory problem with Interop
GC.Collect();
GC.WaitForPendingFinalizers();
}
#endregion
#region Take byte[] of the excel
byte[] result = null;
using (FileStream fs = new FileStream(#"c:\temp\DataSetToExcel.xlsx", FileMode.Open, FileAccess.Read))
{
BinaryReader reader = new BinaryReader(fs);
result = reader.ReadBytes((int)fs.Length);
}
#endregion
#region Delete the excel from the server
File.Delete(#"c:\temp\DataSetToExcel.xlsx");
#endregion
return result;
}
}
So try to use something established by the community already.This is pretty much full example how to do it with Interop. Personally I prefer to use ACE/JET engines, because there is no memory leaks problems like in the Interop(because of that we are calling the GC in the code). Creation of new sheets with ACE/JET engine is a little bit harder.
I think your string comparison in linq query is a problem..your email address might have different case which could have caused this issue. Try below code
DataTable filteredEducation = dt1.AsEnumerable()
.Where(x => dt.AsEnumerable()
.Any(z => z.Field<string>("Email").Trim().Equals(x.Field<string>("Email").Trim(),StringComparison.CurrentCultureIgnoreCase)))
.CopyToDataTable();
DataTable filteredEmployee = dt2.AsEnumerable()
.Where(x => dt.AsEnumerable()
.Any(z => z.Field<string>("Email").Trim().Equals(x.Field<string>("Email").Trim(),StringComparison.CurrentCultureIgnoreCase)))
.CopyToDataTable();
I had done the same export problem by manual export. First, i need to prepare a responce http responce properly, than add all headers(with rowsapn and colspan attributes) of your tables and then populate data:
//this fun is called after click on export button for example
public void Export(string fileName, GridView gv)
{
try
{
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.AddHeader("content-disposition", string.Format("attachment; filename={0}", String.Format("{0}.xls", fileName)));
HttpContext.Current.Response.AddHeader("Content-Transfer-Encoding", "utf-8");
HttpContext.Current.Response.Buffer = true;
HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
HttpContext.Current.Response.Write(#"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.0 Transitional//EN"">");
HttpContext.Current.Response.Charset = "utf-8";//"windows-1251";//
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8");
using (StringWriter sw = new StringWriter())
{
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
// Create a table to contain the grid
Table table = new Table();
table.Width = Unit.Percentage(100);
// include the gridline settings
table.GridLines = gv.GridLines;
//header
TableRow r = new TableRow();
TableCell cell = new TableCell()
{
ColumnSpan = 18,
Text = fileName,
BackColor = Color.LightGray,
HorizontalAlign = HorizontalAlign.Center
};
cell.Font.Size = new FontUnit(14);
r.Cells.Add(cell);
table.Rows.Add(r);
GridViewRow row;
int rowSpan = 0;
//second row
row = CreateSecondHeaderRow();
table.Rows.AddAt(1, row);
//first row
row = CreateFirstHeaderRow(row, rowSpan);
table.Rows.AddAt(1, row);
// add each of the data rows to the table
for (int j = 0; j < gv.Rows.Count; j++)
{
//Set the default color
gv.Rows[j].BackColor = System.Drawing.Color.White;
for (int i = 0; i < gv.Rows[j].Cells.Count; i++)
{
gv.Rows[j].Cells[i].BackColor = System.Drawing.Color.White;
gv.Rows[j].Cells[i].Width = gv.Columns[i].ItemStyle.Width;
gv.Rows[j].Cells[i].Font.Size = gv.Columns[i].ItemStyle.Font.Size;
gv.Rows[j].Cells[i].Font.Bold = gv.Columns[i].ItemStyle.Font.Bold;
gv.Rows[j].Cells[i].Font.Italic = gv.Columns[i].ItemStyle.Font.Italic;
//aligh
if (i == 0)
{
gv.Rows[j].Cells[i].Style["text-align"] = "center";
}
else
{
gv.Rows[j].Cells[i].Style["text-align"] = "right";
}
//for alternate
if (j % 2 != 1) gv.Rows[j].Cells[i].BackColor = Color.LightSteelBlue;
}
table.Rows.Add(gv.Rows[j]);
}
table.RenderControl(htw);
// render the htmlwriter into the response
HttpContext.Current.Response.Write(sw);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
}
}
}
catch (Exception ex)
{
this._hasError = true;
ShowError(ex);
}
}
private TableHeaderCell CreateHeaderCell(string text = null, int rowSpan = 0, int columnSpan = 0, Color backColor = default(Color), Color foreColor = default(Color))
{
if (object.Equals(backColor, default(Color))) backColor = Color.LightGray;
if (object.Equals(foreColor, default(Color))) foreColor = Color.Black;
return new TableHeaderCell
{
RowSpan = rowSpan,
ColumnSpan = columnSpan,
Text = text,
BackColor = backColor
};
}
private GridViewRow CreateFirstHeaderRow(GridViewRow row, int rowSpan)
{
row = new GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Insert);
TableHeaderCell cell = CreateHeaderCell("Surplus %");
row.Controls.Add(cell);
cell = CreateHeaderCell("The date", columnSpan: 2);
row.Controls.Add(cell);
if (this.WithQuantity)
{
cell = CreateHeaderCell("Total Quantity", 2 + rowSpan, backColor: Color.Yellow);
row.Controls.Add(cell);
}
cell = CreateHeaderCell("Total Amount", 2 + rowSpan);
row.Controls.Add(cell);
cell = CreateHeaderCell("Has elapsed periods from start", columnSpan: (this.WithQuantity ? (SurplusUtil.TheColumnsNumbers * 2) : SurplusUtil.TheColumnsNumbers));
row.Controls.Add(cell);
if (this.WithQuantity)
{
cell = CreateHeaderCell("Quantity <br style='mso-data-placement:same-cell;' /> surplus", 2 + rowSpan, backColor: Color.Yellow);
row.Controls.Add(cell);
}
cell = CreateHeaderCell("Principal <br style='mso-data-placement:same-cell;' /> surplus", 2 + rowSpan);
row.Controls.Add(cell);
return row;
}
private GridViewRow CreateSecondHeaderRow()
{
GridViewRow row = new GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Insert);
TableHeaderCell cell = CreateHeaderCell("Period number", rowSpan: ((this.WithQuantity) ? 2 : 0));
row.Controls.Add(cell);
cell = CreateHeaderCell("from", rowSpan: ((this.WithQuantity) ? 2 : 0));
row.Controls.Add(cell);
cell = CreateHeaderCell("to", rowSpan: ((this.WithQuantity) ? 2 : 0));
row.Controls.Add(cell);
for (int i = 0; i < SurplusUtil.TheColumnsNumbers; i++)
{
cell = CreateHeaderCell(i.ToString(),
columnSpan: ((this.WithQuantity) ? 2 : 0),
backColor: System.Drawing.Color.FromArgb(198, 239, 206),
foreColor: System.Drawing.Color.FromArgb(0, 97, 0));
row.Controls.Add(cell);
}
return row;
}

Export SQL Data to an EXISTING Excel File (Specify Sheet)

The following code exports data to a excel file. It creates the file and creates a new sheet.
StringBuilder query = new StringBuilder();
query.Append("SELECT * from dbo.PastAdjs");
SQL.DataTable dtClients = new SQL.DataTable();
using (SqlConnection cn = new SqlConnection(conStr))
{
using (SqlDataAdapter da = new SqlDataAdapter(query.ToString(), cn))
{
da.Fill(dtClients);
progressBar1.Value = 20;
textBox1.Text = "20%";
}
//Create Excel workbook for export
Excel.Application oXL;
Excel._Workbook workbook;
Excel._Worksheet oSheet;
oXL = new Excel.Application();
oXL.Visible = false;
workbook = (Excel._Workbook)(oXL.Workbooks.Add(Missing.Value));
oSheet = (Excel._Worksheet)workbook.ActiveSheet;
Excel.Worksheet newWorksheet;
int sheetamt = 4;
for (int t = 1; t < sheetamt + 1; t++)
{
newWorksheet = (Excel.Worksheet)oXL.Worksheets.Add();
}
int count = workbook.Worksheets.Count;
Excel.Worksheet addedSheet = workbook.Worksheets.Add(Type.Missing,
workbook.Worksheets[count], Type.Missing, Type.Missing);
// creating Excel Application
Microsoft.Office.Interop.Excel._Application app = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel._Worksheet worksheet1 = null;
worksheet1 = workbook.Sheets[1];
Microsoft.Office.Interop.Excel.Worksheet worksheet = (Worksheet)worksheet1;
worksheet1.Name = "PastAdjs";
DataColumnCollection dcCollection = dtClients.Columns;
for (int i = 1; i < dtClients.Rows.Count + 1; i++)
{
for (int j = 1; j < dtClients.Columns.Count + 1; j++)
{
if (i == 1)
worksheet1.Cells[i, j] = dcCollection[j - 1].ToString();
else
worksheet1.Cells[i, j] = dtClients.Rows[i - 1][j - 1].ToString();
}
}
oXL.ActiveWorkbook.SaveCopyAs(filename);
oXL.ActiveWorkbook.Saved = true;
oXL.Quit();
How can I modify this to save to an existing worksheet in an existing excel file?

Categories

Resources