My worksheet is initially named in the 5th line of my code, but I want to rename it based off the workbook name in my case statement. It is not getting renamed. How to fix??
DateTime d = DateTime.Today;
string s = d.ToString("MMddyyyy");
using (ExcelPackage pck = new ExcelPackage())
{
ExcelWorksheet objWorksheet = pck.Workbook.Worksheets.Add("Sheet 1");
objWorksheet.Cells["A1"].LoadFromDataTable(dataTable, true);
switch (pageName)
{
case "abcd":
worksheetName = "abcd";
workbookName = "abcd_" + s + ".xlsx";
objWorksheet.Cells["A1:K20"].AutoFitColumns();
break;
}
}
Looks like you are modifying some unrelated local variable. You would need to modify the Name property on the sheet object:
objWorksheet.Name = "abcd";
Related
I'm using EPPlus to write data to Excel, which works great. I'm writing a header row from column A to column AI and am using the code below to write the data
(subset of the code)
using (ExcelPackage pck = new ExcelPackage())
{
ExcelWorksheet ws = pck.Workbook.Worksheets.Add(customer);
ws.Cells["A1"].Value = "First Name";
ws.Cells["B1"].Value = "Last Name";
ws.Cells["C1"].Value = "Address1";
ws.Cells["D1"].Value = "Address2";
ws.Cells["E1"].Value = "City";
ws.Cells["F1"].Value = "State";
ws.Cells["G1"].Value = "Zip";
ws.Cells["H1"].Value = "Phone";
//keep writing data to I, J, K, L, etc
ws.Cells["AF1"].Value = "Hire Date";
ws.Cells["AG1"].Value = "Manager Name";
ws.Cells["AH1"].Value = "Manager Hire Date";
ws.Cells["AI1"].Value = "Simlcam Number";
FileInfo fi = new FileInfo("C:\\Test\\EPPlusWorkbook.xlsx");
await pck.SaveAsAsync(fi);
}
Now this code writes headers perfectly, UNTIL it reaches cell AF1 then for whatever reason the no further header info is written to the workbook.
Stepping thro the code shows that the lines of code are hit so there is no error displayed.
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();
}
So I have this code for a window:
public partial class List : Window
{
DataTable table = null;
ExcelWorksheet ws = null;
string user = System.Environment.UserName;
public void Initialize()
{
string path = "Log.xlsx";
FileInfo file = new FileInfo(path);
try
{
if (File.Exists(path))
{
using (ExcelPackage pack = new ExcelPackage(file))
{
bool sheetfound = false;
//runs through each sheet to find a specific one
foreach (ExcelWorksheet sheet in pack.Workbook.Worksheets)
{
if (sheet.Name.Equals(user))
{
sheetfound = true;
ws = pack.Workbook.Worksheets[user];
break;
}
}
//Creates new sheet if it hasn't found the specific one
if (!(sheetfound))
{
ws = MainWindow.Create_Worksheet(pack);
pack.Save();
}
}
}
else
{
using (ExcelPackage pack = new ExcelPackage(file))
{
ExcelWorksheet ws = MainWindow.Create_Worksheet(pack);
pack.Save();
}
}
}
catch (Exception ex)
{
MessageBox.Show("Exception caught:\n\n" + ex as string, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
fUpdate(new Object, new RoutedEventArgs);
}
public void fUpdate(object sender, RoutedEventArgs e)
{
table.Rows.Clear();
MessageBox.Show(ws.Dimension.End.Row.ToString());
}
}
and this one from the main window:
public partial class MainWindow : Window
{
public static ExcelWorksheet Create_Worksheet(ExcelPackage pack)
{
ExcelWorksheet ws = pack.Workbook.Worksheets.Add(System.Environment.UserName);
ws.Cells[1, 1].Value = "Date";
ws.Cells[1, 2].Value = "Time";
ws.View.FreezePanes(2, 1);
return ws;
}
}
What this is supposed to do right now is, when the second window launches, it sets the Excel file and worksheet. I used Quickwatch to see if it works and it does work, ws gets set to the specific sheet that I wanted and ws.Dimension.End.Row returns 1. However, after it gets out of the try-catch part (once it reaches fUpdate), ws.Dimension.End.Row suddenly throws a NullReferenceException. I checked and ws is still the same ExcelWorksheet object and it didn't go through anything (that I know of) that would change its value. What causes this error? Thanks!
(ws returns the ExcelWorksheet object but ws.Dimensions return the exception)
The Dimension object of the ExcelWorksheet will be null if the worksheet was just initialized and is empty.
For example:
ExcelWorksheet worksheet = new ExcelPackage().Workbook.Worksheets.Add("Sheet1");
Console.WriteLine(worksheet.Dimension.End.Row);
This code will throw a NullReferenceException since the Dimension object is null.
On the other hand:
ExcelWorksheet worksheet = new ExcelPackage().Workbook.Worksheets.Add("Sheet1");
worksheet.Cells[1, 1].Value = "Some text value";
Console.WriteLine(worksheet.Dimension.End.Row);
This code will not throw an exception since the Dimension object was initialized by adding content to the worksheet.
If the loaded ExcelWorksheet already contains data, you will not face this issue.
You may get NullReferenceException if your file doesn't exists. In this case you're getting into ELSE block and assigning created WorkSheet to a local method variable instead of class variable.
using (ExcelPackage pack = new ExcelPackage(file))
{
// ExcelWorksheet ws = MainWindow.Create_Worksheet(pack); // wrong
ws = MainWindow.Create_Worksheet(pack); // right
pack.Save();
}
For anyone coming along years later like me and facing this issue. This also happens if the ExcelPackage is disposed.
Specifically I had a method where I had
using ExcelPackage excelPackage = new ExcelPackage(fi);
return excelPackage.Workbook.Worksheets.First();
This returns a worksheet, but because the ExcelPackage is disposed when the method is exited, the Dimensions property is null (as are many other properties).
I have followed the routine used here to copy a worksheet in a workbook into the same workbook by using .AddPart<>() and a temporary workbook to serve as a middleman, but have come up with some issues. Prior to copying the worksheet, I have made modifications to it. However, the copied version of the worksheet retains the original sheet, not the modified one. Here's the code:
Document = SpreadsheetDocument.Open(filename, true);
SetupPages(0, nSections);
CopySheet(1);
SetupPages() simply gets a worksheet which has a table with only one row and then copies that row nSections - 1 times, so that the table ends up with nSections rows. This works.
CopySheet() has the following code:
private void CopySheet(int sNum)
{
var tempSheet = SpreadsheetDocument.Create(new MemoryStream(), SpreadsheetDocumentType.Workbook);
WorkbookPart tempWBP = tempSheet.AddWorkbookPart();
var part = Document.XGetWorkSheetPart(sNum);
WorksheetPart tempWSP = tempWBP.AddPart<WorksheetPart>(part);
var copy = Document.WorkbookPart.AddPart<WorksheetPart>(tempWSP);
var sheets = Document.WorkbookPart.Workbook.GetFirstChild<Sheets>();
var sheet = new Sheet();
sheet.Id = Document.WorkbookPart.GetIdOfPart(copy);
sheet.Name = "AAA";
sheet.SheetId = (uint)sheets.ChildElements.Count + 1;
sheets.Append(sheet);
}
This method gets the desired workSheetPart and uses tempSheet.AddPart<>() to perform a deep copy of the desired part and then uses it again to deep copy it back into the original document. This way all the referenced objects contained within the desired workSheetPart are also copied.
This works, in as much as I now have a copy of the workSheet in my original document. However, all the modifications made by SetupPages() prior to calling CopySheet() do not appear in the copied workSheet. So I now have the original Sheet with (in this example) 11 rows and the copied Sheet with only 1 row.
I have tried placing a Document.WorkBookPart.WorkBook.Save() between SetupPages() and CopySheet(), to see if "saving the changes" would make them available to be copied as well, but to no avail.
Is there any OpenXML trick I am unaware of?
EDIT: Using the debugger I have just noticed that part.WorkSheet.ChildElements.Count = 15 (the expected number of rows after SetupPages). However, tempWBP.WorkSheet.ChildElements.Count = 5 (the number of rows in the original sheet prior to the modifications of SetupPages). For whatever reason, the new Rows added by my program are not being deep-copied. Now this I just don't understand.
Should it have something to do with some improper binding of the rows on my part or something, here's the definition of SetupPages():
public void SetupPages(int p, int nSections)
{
Regex rn = new Regex("[0-9]+");
Regex rs = new Regex("[A-Z]+");
SheetData sData = Document.XGet<SheetData>(2 * p + 1);
for (uint i = 1; i < nSections; i++)
{
var r = sData.ChildElements.GetItem(4).Clone() as Row;
r.RowIndex.Value += i;
foreach (OpenXmlElement _c in r.ChildElements)
{
var c = _c as Cell;
Match mn = rn.Match(c.CellReference.Value);
Match ms = rs.Match(c.CellReference.Value);
string str = (int.Parse(mn.Value) + i).ToString();
c.CellReference.Value = ms.Value + str;
}
(r.FirstChild as Cell).CellValue = new CellValue((i + 1).ToString());
sData.Append(r);
}
}
EDIT 2: I've been able to make the copy work fully, but it's very unelegant and doesn't fix what is clearly an error in the code, but merely an emergency measure to pretend that there isn't a problem. I basically get a clone of the original SheetData (which contains the modifications done in SetupPages) and set it as the SheetData of the copied Sheet. I'm just posting this here for information purposes, but if someone could still please point out what is wrong in the code that I'm not seeing, I'll be quite thankful. Here's the "hacked" version of CopySheet(), if anyone is interested.
private void CopySheet(int sNum)
{
var tempSheet = SpreadsheetDocument.Create(new MemoryStream(), SpreadsheetDocumentType.Workbook);
WorkbookPart tempWBP = tempSheet.AddWorkbookPart();
var part = Document.XGetWorkSheetPart(sNum);
var b = part.Worksheet.ChildElements[5].Clone() as SheetData;
WorksheetPart tempWSP = tempWBP.AddPart<WorksheetPart>(part);
var copy = Document.WorkbookPart.AddPart<WorksheetPart>(tempWSP);
copy.Worksheet.RemoveChild<SheetData>(copy.Worksheet.ChildElements[5] as SheetData);
copy.Worksheet.InsertAt<SheetData>(b, 5);
var sheets = Document.WorkbookPart.Workbook.GetFirstChild<Sheets>();
var sheet = new Sheet();
sheet.Id = Document.WorkbookPart.GetIdOfPart(copy);
sheet.Name = "AAA";
sheet.SheetId = (uint)sheets.ChildElements.Count + 1;
sheets.Append(sheet);
}
I've solved this as best I can (and from what I've gathered from other forums I've asked, as best "they" can) by closing and opening the file prior to creating the copies. This makes the changes permanent and then, when copied, the changes are copied, too. With this, the "hack" described above becomes unnecessary. The final version of the code therefore became (with a change to avoid SheetID and Sheet.Name conflicts):
private void CopySheet(int sNum, int pNum, string type)
{
var tempSheet = SpreadsheetDocument.Create(new MemoryStream(), SpreadsheetDocumentType.Workbook);
WorkbookPart tempWBP = tempSheet.AddWorkbookPart();
var part = Document.XGetWorkSheetPart(sNum);
WorksheetPart tempWSP = tempWBP.AddPart<WorksheetPart>(part);
var copy = Document.WorkbookPart.AddPart<WorksheetPart>(tempWSP);
var sheets = Document.WorkbookPart.Workbook.GetFirstChild<Sheets>();
var sheet = new Sheet();
sheet.Id = Document.WorkbookPart.GetIdOfPart(copy);
sheet.Name = "Phase " + pNum + " " + type;
uint id = 1;
bool valid = false;
while (!valid)
{
uint temp = id;
foreach (OpenXmlElement e in sheets.ChildElements)
{
var s = e as Sheet;
if (id == s.SheetId.Value)
{
id++;
break;
}
}
if (temp == id)
valid = true;
}
sheet.SheetId = id;
sheets.Append(sheet);
}
Below is my code to read existing excel file:
FileInfo newFile = new FileInfo("C:\\Excel\\SampleStockTakeExceptionReport.xlsx");
using (ExcelPackage xlPackage = new ExcelPackage(newFile))
{
var ws = xlPackage.Workbook.Worksheets.Add("Content");
ws.View.ShowGridLines = false;
ws.Column(4).OutlineLevel = 1;
ws.Column(4).Collapsed = true;
ws.Column(5).OutlineLevel = 1;
ws.Column(5).Collapsed = true;
ws.OutLineSummaryRight = true;
//Headers
ws.Cells["B1"].Value = "Name";
ws.Cells["C1"].Value = "Size";
ws.Cells["D1"].Value = "Created";
ws.Cells["E1"].Value = "Last modified";
ws.Cells["B1:E1"].Style.Font.Bold = true;
System.Diagnostics.Process.Start("C:\\Excel\\SampleStockTakeExceptionReport.xlsx");
}
While I run the code. It throws a runtime error.
Error.
System.InvalidOperationException: A worksheet with this name already exists in the workbook
at OfficeOpenXml.ExcelWorksheets.Add(String Name)
at Report.Form1.ExportToExcel1(DataTable Tbl, String ExcelFilePath) in C:\SMARTAG_PROJECT\SUREREACH\EXCEL\Report\Report\Form1.cs:line 43
It's pretty straight forward, either:
first check if the worksheet exists and only if it doesn't then execute your code
just remove the existing worksheet if it exists and add it again with your values
modify those values for the existing worksheet "Content"
Try something like this maybe:
FileInfo newFile = new FileInfo("C:\\Excel\\SampleStockTakeExceptionReport.xlsx");
using (ExcelPackage xlPackage = new ExcelPackage(newFile))
{
//Check if worksheet with name "Content" exists and retrieve that instance or null if it doesn't exist
var ws = xlPackage.Workbook.Worksheets.FirstOrDefault(x => x.Name == "Content");
//If worksheet "Content" was not found, add it
if (ws == null)
{
ws = xlPackage.Workbook.Worksheets.Add("Content");
}
//Rest of code
}