EPPLUS cannot delete worksheet >> "Part does not exist" (System.InvalidOperationException) - c#

I have build an excel workbook with several worksheets as a reporting template.
The task is done by creating a new excelpackage from the designed xlsx file and fill it up with data.
The template xlsx containing charts and data worksheets.
var packageReport = new ExcelPackage();
packageReport.Load(new memoryStream(Properties.Resources.Reporting_Template));
packageReport.Workbook.Worksheets.Delete(3) // not working >> Exception
packageReport.Workbook.Worksheets.Delete(packageReport.Workbook.Worksheets["Name"]) // not working >> Exception
var ws = packageReport.Workbook.Worksheets.FirstOfDefault(w => w.Name == "Name");
packageReport.Workbook.Worksheets.Delete(ws); // Exception
Also have tried to select the worksheet in a object var before, with also no luck ... Cannot delete any of my newly created worksheets ... :(
Any idea is welcome ...
Thx. Dudes.
Current EPPlus.dll (Version: 4.0.5.0, Runtime Version: v2.0.50727)
Addition:
Also tried to use the template constructor function to generate a copy of the excel stored as a memorystream object with no luck.

Related

Adding a table to an existing excel file with spreadsheetgear

I use Spreadsheetgear to export the results of custom SQL queries as excel files.
Now I want to improve this system: The user will be able to upload an excel template file into the database (currently as varbinary). For example, it could have one worksheet with calculations, then when exporting data into that template it'll fill a different worksheet with the datatable from the query.
Can spreadsheetgear do this? If so, how does it work - mainly how can I load an existing excel file as a Spreadsheetgear workbook/workbookset? I could not find anything in their documentation (though I am still looking).
Edit: Solved.
I create the workbook manually, load the template from the database as a byte[], then open said template with the OpenFromMemory function:
// Create workbookSet
SpreadsheetGear.IWorkbookSet workbookSet = SpreadsheetGear.Factory.GetWorkbookSet();
// Create a new empty workbook in the workbookSet.
SpreadsheetGear.IWorkbook workbook = workbookSet.Workbooks.Add();
if(TemplateID != -1) // If this case requires a template
{
// Get template from SQL database (.xlsx stored as varbinary(max))
byte[] template = GetTemplateByID(VorlagenID);
workbook = workbookSet.Workbooks.OpenFromMemory(template);
}
// Create export worksheet
SpreadsheetGear.IWorksheet worksheet = workbook.Worksheets[0];
worksheet.Name = "Export";
[...]
Templates always use the Worksheet[1] in my case, but it should be easy to create a Worksheet[1] for the export.
Yes it is possible to set up pre-constructed template files using SpreadsheetGear. We use this extensively using .NET / C# / MSSSQL. The method allows you to create quite sophisticated templates and then simply add the required data. This of course includes any calculations you build into the template.
Method 1 - Store the template on a webserver, extract and write the created user spreadsheet to a folder on the web server. Return the filename to allow extraction by code or by the user from the server.
public static String SaveTemplateSpreadsheetToServer()
{
// Open the workbook.
var templatename = HostingEnvironment.MapPath("~/Files/MyTemplate.xlsx");
var workbook = Factory.GetWorkbook(templatename );
// Read and write to the spreadsheet
// Save a copy to disk and return filename
var filename = "The_exported_file.xlsx";
var filePath = HostingEnvironment.MapPath("~/FilesTemp/" + filename);
workbook.SaveAs(filePath, FileFormat.OpenXMLWorkbook);
// close workbook
workbook.Close();
// Return the filename
return fileName;
}
Method 2: Store the template on a webserver, extract and save modified spreadsheet as a byte array. Download directly an attachment
public static byte[] SaveTemplateSpreadsheetToServer()
{
// Open the workbook.
var templatename = HostingEnvironment.MapPath("~/Files/MyTemplate.xlsx");
var workbook = Factory.GetWorkbook(templatename );
// Read and write to the spreadsheet
// Save as byte array and send to user
var byteArray = workbook.SaveToMemory(FileFormat.OpenXMLWorkbook);
// close workbook
workbook.Close();
// Return the byte array
return byteArray;
}
We have done some work with binary template files saved in a database but find it more convenient to work with physical template files on a web server. It is easier to manage changes to the template.
My only caution is to avoid working with very big templates that have lots of "junk" in them (e.g. images). The process becomes affected by the time it takes to load the file into memory prior to the read / write / export activity. Less than 1MB is ideal and less than 2MB is manageable.

EPPLUS To Clear Contents of A Range Of Cells

I want to use EPPLUS to clear a range of cells. I tried the syntax below, but it gives me an error of
object reference not set to an instance of an object
What would be the proper way to clear the contents of cells A24:C36 with EPPLUS?
ExcelPackage package = new ExcelPackage();
ExcelWorksheet ws = package.Workbook.Worksheets["Sheet1"];
ws.Cells["A24:C36"].Clear();
Your code is correct. I think the .xlsx file does not have Worksheets with Sheet1 name.
For example, I created this excel file like this:
I wanted to erase A24:C36. I encountered null reference error before executing ws.Cells["A24:C36"].Clear(); like this:
If I use code below instead of it, it works properly (Sheet2).
ExcelPackage package = new ExcelPackage();
ExcelWorksheet ws = package.Workbook.Worksheets["Sheet2"];
ws.Cells["A24:C36"].Clear();
Notice that having no value in A24:C36 does not make an error.

Appending new cells breaks the excel file

This might be the duplicate as many posts refer to this kind of issues but I could not find an exact answer to this case.
So, what I have is an Excel file where cell "E4" contains a formula "=C4+D4". All other cells are empty, which means I cannot search or get them via OpenXml, simply because they do not exist in Xml. So in order to fill the cells "C4" and "D4" I have to create them (like this:)
var cell = new Cell(){
CellReference = new StringValue("C4"),
DataType = new EnumValue<CellValues>(CellValues.Number),
CellValue = new CellValue("123")
}
the same for cell "D4" and then append these cells to the row
row.Append(cell);
After I open the excel file it show an error "Excel found unreadable content in file.xlsx. Do you want to recover the contents of this workbook? If you trust the source of this workbook, click Yes."
I checked and when there is no formula in excel file the cells are appended correctly.
So my question is, using OpenXml how do I append cells in Excel file, which contains formula, so that not to break the file?
So the XML is malformed and corrupted the has file, hence the error:
Excel found unreadable content in file
To troubleshoot and fix this I suggest you compare the manually created xlsx to the programmatically created xlsx.
To do this you rename both files extensions from XLSX to ZIP > extract them to different folders > use a WinDiff tool (or better the "OpenXML SDK Productivity Tool") to compare the files.
Once you find how its malformed change your code to try and fix it up.
I solved my problem using EPPLUS
using (ExcelPackage excelPackage = new ExcelPackage(fileStream))
{
ExcelWorkbook excelWorkBook = excelPackage.Workbook;
ExcelWorksheet excelWorksheet = excelWorkBook.Worksheets.First();
excelWorksheet.Cells["C4"].Value = "123";
excelWorksheet.Cells["D4"].Value = "321";
excelPackage.SaveAs(memoryStream);
}

ClosedXML Add WorkSheet with Conditional Formatting

I am using ClosedXML to add new worksheet to existing Excel document.
It works fine for normal Excel document.
But if a excel document sheet contains conditional formatting on some cell then it throws error
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at ClosedXML.Excel.XLCFConverters.Convert(IXLConditionalFormat conditionalFormat, Int32 priority, SaveContext context)
at ClosedXML.Excel.XLWorkbook.GenerateWorksheetPartContent(WorksheetPart worksheetPart, XLWorksheet xlWorksheet, SaveContext context)
at ClosedXML.Excel.XLWorkbook.CreateParts(SpreadsheetDocument document)
at ClosedXML.Excel.XLWorkbook.CreatePackage(String filePath, SpreadsheetDocumentType spreadsheetDocumentType)
at ClosedXML.Excel.XLWorkbook.SaveAs(String file)
Below is the sample code
using (var excelDoc = new ClosedXML.Excel.XLWorkbook(strFilePath))
{
excelDoc.Worksheets.Add("New Result Sheet");
excelDoc.SaveAs(strFilePathSave);
}
Please help how to fix this issue.
XlsIO is a .NET library that reads and writes Excel 2003/2007/2010/2013/2016 files. Using XlsIO, you can add/modify a worksheet with conditional formatting very easily without issues. The whole suite of controls is available for free (commercial applications also) through the community license program if you qualify. The community license is the full product with no limitations or watermarks.
Step 1: Create a console application
Step 2: Add reference to Syncfusion.XlsIO.Base and Syncfusion.Compression.Base, you can add these reference to your project using NuGet also.
Step 3: Copy & paste the following code snippet.
The following code snippet illustrates how to add a worksheet with conditional formatting using XlsIO
using (ExcelEngine excelEngine = new ExcelEngine())
{
//Instantiate the excel application object.
IApplication application = excelEngine.Excel;
application.DefaultVersion = ExcelVersion.Excel2013;
//Open the workbook
IWorkbook workbook = application.Workbooks.Open("Input.xlsx");
(workbook.Worksheets as WorksheetsCollection).Add("NewSheet");
IWorksheet worksheet = workbook.Worksheets[1];
IConditionalFormats condition = worksheet.Range["A1"].ConditionalFormats;
IConditionalFormat condition1 = condition.AddCondition();
condition1.FormatType = ExcelCFType.CellValue;
condition1.Operator = ExcelComparisonOperator.Between;
condition1.FirstFormula = "10";
condition1.SecondFormula = "20";
condition1.BackColor = ExcelKnownColors.Red;
worksheet.Range["A1"].Number = 13;
//Save the workbook
workbook.SaveAs("AddedWorkbook.xlsx");
}
Kindly refer the sample to achieve this scenario and the sample can be downloaded from following location.
Download Demo
For further information about XlsIO, please refer our help documentation
Note: I work for Syncfusion

Does ClosedXML support setting a worksheet's zoom level?

I am using closedXML to generate an Excel file from C# and I am trying to see if there is anyway to set the zoom level of a worksheet. I can't find this in any of the documentation or from googling?
Does anybody know how to do this?
It's now possible, starting with ClosedXML version 0.87.0, via the IXLSheetView.ZoomScale property.
using Excel = ClosedXML.Excel;
var wb = new Excel.XLWorkbook();
Excel.IXLWorksheet ws = wb.AddWorksheet("zoom");
Excel.IXLSheetView view = ws.SheetView;
/* Value can be set between 10 and 400 */
view.ZoomScale = 85;
You can check the IXLSheetView source code for more information.
Update for version 0.87+: https://stackoverflow.com/a/52755386/2610249
No, ClosedXML does not support setting the zoom. The option that johny links to is only for scaling of the pages when printing.
There is a feature request on the ClosedXML page, but no answer from the developer.
As previously answered, you can't, but I've found a way around it which works well:
Create a template Excel file in advance, with all sheets' zoom levels set to how you want them.
When you create your workbook, instead of:
public XLWorkbook CreateWorkbook()
{
XLWorkbook workbook = new XLWorkbook();
IXLWorksheet worksheet = workbook.AddWorksheet("First sheet");
// ...
return workbook;
}
do this:
public XLWorkbook CreateWorkbookWithZoom()
{
XLWorkbook workbook = new XLWorkbook(#"C:\your template file.xlsx");
IXLWorksheet worksheet = workbook.Worksheet(1);
worksheet.Name = "First sheet";
// ...
return workbook;
}
where C:\your template file.xlsx is the path of your template file.
I think you can also handle having a variable number of sheets, by copying existing (blank) worksheets instead of creating new ones. You can get creative with having different blank template worksheets to choose from, if you need to set the zoom level dynamically.
A pull request for this has been logged at https://github.com/ClosedXML/ClosedXML/pull/180

Categories

Resources