How to copy worksheet data and style with EPPlus C#? - c#

I am saving data to a new worksheet with EPPlus. But it doesn't copy the styles of the worksheet I use as a template. How can I do that?
As seen in the picture, the cell height of the template is 25, while the cell height of the new worksheet I created using the template is 18. I want the cell height in the new worksheet to be 25 as well.
My code is here..
FileInfo template = new FileInfo(path + #"\Template\template.xlsx");
using (ExcelPackage package = new ExcelPackage(template))
{
FileInfo newFile = new FileInfo(fileCheck);
using(ExcelPackage pack = new ExcelPackage(newFile))
{
ExcelWorksheet ws0 = package.Workbook.Worksheets[0];
ws0.Cells["A8"].Value = texedit2.Text;
pack.Workbook.Worksheets.Add("Sheet2", ws0);
pack.SaveAs(newFile);
}
}
Is there any other solution?

The best way I've found to do this loop through each row in the new worksheet and manually set the height to match the corresponding row in the template.
ExcelWorksheet ws0 = package.Worksheets[0];
ExcelWorksheet newWorksheet = pack.Workbook.Worksheets.Add("Sheet2", templateWorksheet);
for(int i = 0; i < ws0.Dimensions.Row + 1; i++)
{
newWorksheet.Rows[i].CustomHeight = true;
newWorksheet.Rows[i].Height = ws0.Rows[i].Height;
}

Related

Insert into Existing excel file using EPP on C#

I want to insert value on my excel ,but i have a problem when i run my application, its create a new file excel ,doesnt insert value into existing file,
using (ExcelPackage excel = new ExcelPackage())
{
excel.Workbook.Worksheets.Add("Worksheet1");
// Target a worksheet
var worksheet = excel.Workbook.Worksheets["Worksheet1"];
worksheet.Cells[1, 1].Value = "Name";
worksheet.Cells[2, 1].Value = "ID";
FileInfo excelFile = new FileInfo(#"E:\ExcelTest.xls");
excel.SaveAs(excelFile);
I want my Program insert into existing file ,not create a new one,
how i can solve this?
The EPPlus Wiki Getting Started covered this exact scenario.
FileInfo excelFile = new FileInfo(#"E:\ExcelTest.xls");
using (ExcelPackage excel = new ExcelPackage(excelFile))
{
// Target a worksheet
var worksheet = excel.Workbook.Worksheets["Worksheet1"];
worksheet.Cells[1, 1].Value = "Name";
worksheet.Cells[2, 1].Value = "ID";
excel.Save();
}

Extract values from a list and save it to an existing Excel sheet in c#

I have an existing Excel sheet which has headers. I get data from my server and place it in my WPF DataGrid and it looks like this:
On a click of a button, I need to place the values from my list to a particular sheet in my existing Excel workbook. I can actually get the values from a WINFORM DataGrid like this:
var xlApp = new Excel.Application();
Excel.Worksheet sheet = new Excel.Worksheet();
xlApp.Visible = true;
var path = #"D:\Reports\Tag_History.xlsx";
sheet = xlApp.Application.Workbooks.Open(path).Worksheets["Summary"];
var rowCount = dataGrid.Items.Count;
var rowColumn = dataGrid.Columns.Count;
for (int i = 0; i < rowCount - 1; i++)
{
for (int j = 0; j < 7; j++)
{
if (dataGrid[j, i].ValueType == typeof(string))
{
xlsht.Cells[i + 2, j + 1] = "'" + dataGrid[j, i].Value.ToString();
}
else
{
xlsht.Cells[i + 2, j + 1] = dataGrid[j, i].Value.ToString();
}
}
}
but since I am trying to do this in WPF, this code does not work anymore. This is by transferring dataGrid data to an existing excel file. Since I think that transferring list to an existing excel file is better, I have to try this. This is what I have so far:
var xlApp = new Excel.Application();
Excel.Worksheet sheet = new Excel.Worksheet();
xlApp.Visible = true;
var path = #"D:\Reports\Tag_History.xlsx";
sheet = xlApp.Application.Workbooks.Open(path).Worksheets["Summary"];
var range = sheet.Range["A2", "A2"];
foreach (var item in summaryList)
{
range.Value2 = item.TagNumber;
}
This code works but it is only updating a single cell of the excel file.
Can you please show me how to do this? Thank you.
Install Microsoft.Office.Interop.Excel Nuget package in your application. Right-click on your project -> "References" and choose "Manage NuGet Packages...", then just search for Excel. Otherwise, select Tools -> Nuget Package Manager -> Package Manager Console -> then install the Excel nuget (https://www.nuget.org/packages/Microsoft.Office.Interop.Excel/).
Bind the items in DataGrid and then export data to excel as like below,
private void btnExport_Click(object sender, RoutedEventArgs e)
{
Microsoft.Office.Interop.Excel.Application excel = null;
Microsoft.Office.Interop.Excel.Workbook wb = null;
object missing = Type.Missing;
Microsoft.Office.Interop.Excel.Worksheet ws = null;
Microsoft.Office.Interop.Excel.Range rng = null;
// collection of DataGrid Items
var dtExcelDataTable = ExcelTimeReport(txtFrmDte.Text, txtToDte.Text, strCondition);
excel = new Microsoft.Office.Interop.Excel.Application();
wb = excel.Workbooks.Add();
ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.ActiveSheet;
ws.Columns.AutoFit();
ws.Columns.EntireColumn.ColumnWidth = 25;
// Header row
for (int Idx = 0; Idx < dtExcelDataTable.Columns.Count; Idx++)
{
ws.Range["A1"].Offset[0, Idx].Value = dtExcelDataTable.Columns[Idx].ColumnName;
}
// Data Rows
for (int Idx = 0; Idx < dtExcelDataTable.Rows.Count; Idx++)
{
ws.Range["A2"].Offset[Idx].Resize[1, dtExcelDataTable.Columns.Count].Value = dtExcelDataTable.Rows[Idx].ItemArray;
}
excel.Visible = true;
wb.Activate();
wb.SaveCopyAs("excel file location");
wb.Saved = true;
excel.Quit();
}

Open a xls file with SAX approach in .Net and adding several rows (about 100K)

I need your support.
I need to open a .xls file with c# adding about 100k of rows.
I tried several approach, but all approaches run me into memory error, except for OpenXML with SAX Approach. This one works for me.
My problem is I'm able to create excel with 100K rows from the scratch (and it works like a charm), but I'm not able to open a file xls that for example has first row with titles, second row with formulas, and suppose I've to add 100K rows from the third row of this excel.
This is my code.
When i run it, file is cloned but no rows are added...could you please help me?
Thanks
//copy of file
String str_IntermidiateXLSPath = "c:\\testXls3.xlsx";
File.Copy("c:\\testXls.xlsx", str_IntermidiateXLSPath, true);
using (SpreadsheetDocument SpreadsheetDocumentObj = SpreadsheetDocument.Open(str_IntermidiateXLSPath, true))
{
WorkbookPart workbookpart = null;
WorksheetPart worksheetpart = null;
OpenXmlWriter writer = null;
Cell cell = null;
Row row = null;
SpreadsheetDocumentObj.CompressionOption = CompressionOption.SuperFast;
workbookpart = SpreadsheetDocumentObj.WorkbookPart;
worksheetpart = workbookpart.WorksheetParts.First();
writer = OpenXmlWriter.Create(worksheetpart);
writer.WriteStartElement(new Worksheet());
writer.WriteStartElement(new SheetData());
//starting row
for (int i = 3; i < 80; i++)
{
row = new Row();
for (int j = 0; j < 10; j++)
{
cell = new Cell();
row.Append(cell);
cell.DataType = CellValues.InlineString;
cell.InlineString = new InlineString { Text = new Text { Text = "XXX" } };
}
writer.WriteElement(row);
}
writer.WriteEndElement();
writer.WriteEndElement();
writer.Close();
workbookpart.Workbook.Save();
SpreadsheetDocumentObj.Close();
}
Process.Start(str_IntermidiateXLSPath);

Split a large Excel file into multiple, based on row count

I have a C# console application which needs a large Excel to be split into multiple Excel files based on the row count. The code below shows a source file with only 51 rows (including the header column rows) but the final source file will have 100,000+ rows.
The code is trying to skip the very first (header) row and then should copy from rows 2 through 11 and so on--I have the target files set to only 10 rows per file, to make developing faster.
Question So how do I copy rows 2 through 11 and subsequent 10 rows from the source Excel file and paste to multiple target Excel files so that the target files each will have 10 rows?
Here is the almost newly written code. It is loosely based on copying of specific range of excel cells from one worksheet to another worksheet and https://social.msdn.microsoft.com/Forums/vstudio/en-US/afd01976-63d0-4f96-9ba4-e3e2b6cf8d55/excel-with-c-how-to-specify-a-range-?forum=vsto
Now I am able to write 5 Excel files. But the first file has 9 rows (starting from row 2) while 2nd file has only 3 rows, starting with row 10, the 3rd has 13 rows starting, again, with row 10; the last two files have incrementally more rows, both starting with row 10.
So something wrong with my For Loop? Or the way I am selecting the ranges?
string startPath = System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
string filePath_source = Path.Combine(startPath, #"Source_Files\Offers_Source_Temp.xlsx");
string filePath_copiedinto = Path.Combine(startPath, #"Source_Files\ToBeCopiedInto.xlsx");
app = new Excel.Application();
app.DisplayAlerts = false;
book = app.Workbooks.Open(filePath_source);
sheet = (Excel.Worksheet)book.Worksheets.get_Item((1));
int iRowCount = sheet.UsedRange.Rows.Count;
int maxrows = 10;//change this to something like 50,000 later. 01/16/18
int maxloops = iRowCount / maxrows;
int beginrow = 2; //skipping the header row.
Excel.Application destxlApp;
Excel.Workbook destworkBook;
Excel.Worksheet destworkSheet;
Excel.Range destrange;
string srcPath;
string destPath;
//Opening of first worksheet and copying
srcPath = filePath_source;
for (int i = 1; i <= maxloops; i++) {
Excel.Range rng = (Excel.Range)sheet.Range[sheet.Cells[beginrow, 1], sheet.Cells[maxrows, 3]];
rng.Copy(Type.Missing);
//opening of the second worksheet and pasting
destPath = filePath_copiedinto;
destxlApp = new Excel.Application();
destxlApp.DisplayAlerts = false;
destworkBook = destxlApp.Workbooks.Open(destPath, 0, false);
destworkSheet = destworkBook.Worksheets.get_Item(1);
destrange = destworkSheet.Cells[1, 1];
destrange.Select();
destworkSheet.Paste(Type.Missing, Type.Missing);
destworkBook.SaveAs(startPath + "\\Output_Files\\" + beginrow + ".xlsx");
destworkBook.Close(true, null, null);
destxlApp.Quit();
beginrow = beginrow + maxrows;
string blah = null;
}
I would suggest to use OpenXml library to do that task. It is dependency free and supports the whole OpenXml structure.
Here a starting point how to read/write the rows:
using System;
using System.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
// Open the document for editing.
using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(fileName, false))
{
WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();
SheetData sheetData = worksheetPart.Worksheet.Elements<SheetData>().First();
foreach (Row r in sheetData.Elements<Row>())
{
}
}
Now, writing is very similar:
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Create(fileName),
SpreadsheetDocumentType.Workbook))
{
// create the workbook
spreadSheet.AddWorkbookPart();
spreadSheet.WorkbookPart.Workbook = new Workbook (); // create the worksheet
spreadSheet.WorkbookPart.AddNewPart<WorksheetPart>();
spreadSheet.WorkbookPart.WorksheetParts.First().Worksheet = new Worksheet();
// create sheet data
spreadSheet.WorkbookPart.WorksheetParts.First().Worksheet.AppendChild(new SheetData());
// create row
spreadSheet.WorkbookPart.WorksheetParts.First().Worksheet.First().AppendChild(new Row());
}
Got it! In my revised code in the Question, I came close but had some problem in the For Loop; fixed it per the code below. So here is the almost complete code. Thanks everyone for your help!!
try
{
string startPath = System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
string filePath_source = Path.Combine(startPath, #"Source_Files\Offers_Source_Temp.xlsx");
string filePath_copiedinto = Path.Combine(startPath, #"Source_Files\ToBeCopiedInto.xlsx");
app = new Excel.Application();
app.DisplayAlerts = false;
book = app.Workbooks.Open(filePath_source);
sheet = (Excel.Worksheet)book.Worksheets.get_Item((1));
int iRowCount = sheet.UsedRange.Rows.Count;
int countColumns = sheet.UsedRange.Columns.Count;
int maxrows = 10;//change this to something like 50,000 later. 01/16/18
int maxloops = iRowCount / maxrows;
int beginrow = 2; //skipping the header row.
Excel.Application destxlApp;
Excel.Workbook destworkBook;
Excel.Worksheet destworkSheet;
Excel.Range destrange;
string srcPath;
string destPath;
//Opening of first worksheet and copying
srcPath = filePath_source;
for (int i = 1; i <= maxloops; i++) {
/// Excel.Range rng = (Excel.Range)sheet.Range[sheet.Cells[beginrow, 1], sheet.Cells[maxrows, 3]];
Excel.Range startCell = sheet.Cells[beginrow, 1];//not sure the second parameter needed?
Excel.Range endCell = sheet.Cells[beginrow+maxrows-1, 3];//not sure the second parameter needed?
Excel.Range rng = sheet.Range[startCell, endCell];
rng = rng.EntireRow;//so second parameters above should not be needed. But doesn't work without it!
rng.Copy(Type.Missing);
//opening of the second worksheet and pasting
destPath = filePath_copiedinto;
destxlApp = new Excel.Application();
destxlApp.DisplayAlerts = false;
destworkBook = destxlApp.Workbooks.Open(destPath, 0, false);
destworkSheet = destworkBook.Worksheets.get_Item(1);
destrange = destworkSheet.Cells[1, 1];
destrange.Select();
destworkSheet.Paste(Type.Missing, Type.Missing);
destworkBook.SaveAs(startPath + "\\Output_Files\\" + beginrow + ".xlsx");
destworkBook.Close(true, null, null);
destxlApp.Quit();
beginrow = beginrow + maxrows;
}//for loop
}

Setting Font.Bold and Column.Width for Cells in OPEN XML

I've been using OPEN XML to create a spread sheet which can then be downloaded. I want to set the column widths and also change the header to bold. I've done this using Office.Interop.Excel but I'm struggling with this format. My code is below, you can see I've set up a font but have been unable to assign it to my spread sheet, I have got messages saying it's not possible to assign to a tree.
SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(fileName, SpreadsheetDocumentType.Workbook); //Open(fileName, true);
try
{
WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart();
workbookpart.Workbook = new DocumentFormat.OpenXml.Spreadsheet.Workbook();
WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new DocumentFormat.OpenXml.Spreadsheet.Worksheet(new SheetData());
DocumentFormat.OpenXml.Spreadsheet.Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook.AppendChild<DocumentFormat.OpenXml.Spreadsheet.Sheets>(new DocumentFormat.OpenXml.Spreadsheet.Sheets());
Sheet sheet = new Sheet() { Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "Models" };
sheets.Append(sheet);
DocumentFormat.OpenXml.Spreadsheet.Font boldFont = new DocumentFormat.OpenXml.Spreadsheet.Font();
Bold bFontBold = new Bold();
boldFont.Append(bFontBold);
DocumentFormat.OpenXml.Spreadsheet.Worksheet worksheet = new DocumentFormat.OpenXml.Spreadsheet.Worksheet();
SheetData sheetData = new SheetData();
........
Row row = new Row();
Cell cell = new Cell()
{
CellReference = "A" + (intI + 1),
DataType = CellValues.String,
CellValue = new CellValue(ModelBookrowDetail[0])
};
row.Append(cell);
Cell cell2 = new Cell()
{
CellReference = "B" + (intI + 1),
DataType = CellValues.String,
CellValue = new CellValue(ModelBookrowDetail[1])
};
row.Append(cell2);
.........
sheetData.Append(row);
}
worksheet.Append(sheetData);
worksheetPart.Worksheet = worksheet;
spreadsheetDocument.Close();
}
catch
{
spreadsheetDocument.Close();
}
I don't know how set you are on using OpenXml. I might suggest looking into ClosedXml. Up until now it has saved me a lot of manhours. It only has one downside to it, and that is that it doesn't manage Word documents like OpenXml does.
ClosedXml is a more object oriented Open Source Library, and is far more well documented in contrast to what i have experienced with OpenXml.
You can find ClosedXml here:
https://github.com/ClosedXML/ClosedXML
Best of luck
Olliver

Categories