How to create pivot table and save it using NPOI C# package? - c#

I am struggling for creating and saving a pivot table, I ran the code below with no error, but failed to open the excel file.
Here is my code:
public void Execute()
{
IWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = (XSSFSheet)workbook.CreateSheet("sample");
IRow row0 = sheet.CreateRow(0);
row0.CreateCell(0).SetCellValue("test");
row0.CreateCell(1).SetCellValue("a");
row0.CreateCell(2).SetCellValue("b");
IRow row1 = sheet.CreateRow(1);
row1.CreateCell(0).SetCellValue("asd");
row1.CreateCell(1).SetCellValue("das");
row1.CreateCell(2).SetCellValue("fgh");
var tl = row0.GetCell(0);
var br = row1.GetCell(2);
CellReference topLeft = new CellReference(tl);
CellReference botRight = new CellReference(br);
AreaReference aref = new AreaReference(topLeft, botRight);
CellReference pos = new CellReference(3, 3);
XSSFPivotTable pivotTable = sheet.CreatePivotTable(aref, pos);
using (FileStream fileWritter = new FileStream("test.xlsx", FileMode.Create, FileAccess.Write))
{
workbook.Write(fileWritter);
}
}
The error of opening the file:
Removed Part: /xl/pivotCache/pivotCacheDefinition1.xml part with XML error. (PivotTable cache) HRESULT 0x8000ffff Line 1, column 0. Removed Part: /xl/pivotTables/pivotTable1.xml part with XML error. (PivotTable view) HRESULT 0x8000ffff Line 1, column 0.
Please help!

I found the answer on my own: using Microsoft.Office.Interop.Excel to do boring steps in Excel.
I used macro recorder in Excel to generate source code, and then just easily edited the code in any language that I want.

Related

C# Problem opening excel file using `OpenXml` from `byte[]`

I have a problem when saving and opening a file with OpenXml library. Here is my code:
public static void SaveExcel(List<Dictionary<string, object>> listData, List<string> entityTypes, string appName)
{
using (var ms = new MemoryStream())
using (var excel = SpreadsheetDocument.Create(ms, SpreadsheetDocumentType.Workbook))
{
var workBookPart = excel.AddWorkbookPart();
workBookPart.Workbook = new Workbook();
var workSheetPart = workBookPart.AddNewPart<WorksheetPart>();
var workSheetData = new SheetData();
workSheetPart.Worksheet = new Worksheet(workSheetData);
var sheets = workBookPart.Workbook.AppendChild(new Sheets());
var index = 1;
foreach (var entityType in entityTypes)
{
var sheet = new Sheet
{
Id = excel.WorkbookPart.GetIdOfPart(workSheetPart),
SheetId = 1U,
Name = entityType
};
sheets.AppendChild(sheet);
}
workBookPart.Workbook.Save(ms);
File.WriteAllBytes("D:/nothing123.xlsx", ms.ToArray());
}
}
I am pretty sure I did the right thing though I have this error when opening the file:
Excel cannot be opened the file 'nothing123.xlsx' because the file format or file extension is not valid. Verify that the file has not been corrupted and the file extension matches the format of the file.
Any idea whats going on with my code?
I don't know if this is relevant to the tag but I made up my mind to use ClosedXml library since it's much easier to use than OpenXml. I can easily create a DataTable and create an Excel file out of the DataTable which is very convenient. Here is my quick sample code:
Sample Data Table
public DataTable getData() {
DataTable dt = new DataTable();
dt.TableName = "SheetName1";
dt.Columns.Add("FirstName");
dt.Columns.Add("LastName");
var row = dt.NewRow();
row["FirstName"] = "Alvin";
row["LastName"] = "Quezon";
dt.Rows.Add(row);
return dt;
}
Sample Code to Excel to Byte Array
public static byte[] GetExcelBytes(DataTable dataTable)
{
using (var ms = new MemoryStream())
using (var workBook = new XLWorkbook())
{
workBook.Worksheets.Add(dataTable);
workBook.SaveAs(ms);
return ms.ToArray();
}
}
I didn't get any issue when opening the file and with superb minimal code usage.
Hopefully this will help anyone would like to use this in the future.

Open XML Creating Multiple sheets

I am trying to create an Excel file using Open XML C#, where there are multiple sheets in my excel file that needs to be created. Please find my code below and help me with a solution.
When I open the excel only 1 sheet is present, sheet 2 is getting overwritten in sheet 1.
public void CreateExcelFile(string filePath , List<SheetData> excelSheet)
{
var sheetCount = GetSheetCount(filePath);
using (SpreadsheetDocument spreedDoc = SpreadsheetDocument.Create(filePath,
DocumentFormat.OpenXml.SpreadsheetDocumentType.Workbook))
{
Workbook workbook1 = new Workbook();
workbook1.AddNamespaceDeclaration("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
FileVersion fileVersion1 = new FileVersion() { ApplicationName = "xl", LastEdited = "5", LowestEdited = "4", BuildVersion = "9302" };
WorkbookProperties workbookProperties1 = new WorkbookProperties() { FilterPrivacy = true, DefaultThemeVersion = (UInt32Value)124226U };
BookViews bookViews1 = new BookViews();
WorkbookView workbookView1 = new WorkbookView() { XWindow = 240, YWindow = 105, WindowWidth = (UInt32Value)14805U, WindowHeight = (UInt32Value)8010U, ActiveTab = (UInt32Value)2U };
bookViews1.Append(workbookView1);
Sheets sheetCol = new Sheets();
int ctr = 0;
foreach (var sheetToCreate in excelSheet)
{
ctr++;
//WorksheetPart worksheetPart = null;
//worksheetPart = wbPart.AddNewPart<WorksheetPart>();
//var sheetData = new SheetData();
//worksheetPart.Worksheet = new Worksheet(sheetData);
//worksheetPart.Worksheet = new Worksheet(sheetToCreate);
string sheetName = "Sheet";
sheetName += ctr.ToString();
var sheet = new Sheet()
{
Id = "rId" + ctr,
SheetId = (UInt32)ctr,
Name = sheetName
};
sheet.Append(sheetToCreate);
sheetCol.Append(sheet);
//wbPart.Workbook.Sheets.AppendChild(sheet);
//wbPart.Workbook.Append(sheetCol);
workbook1.Sheets.Append(sheet);
//var workingSheet = ((WorksheetPart)wbPart.GetPartById(sheet.Id)).Worksheet;
}
workbook1.Append(fileVersion1);
workbook1.Append(workbookProperties1);
workbook1.Append(bookViews1);
workbook1.Append(sheetCol);
//Set Border
//wbPark
workbook1.Save();
}
}
When dealing with OpenXML, the "OpenXML Productivity Tool" (downloadable from Microsoft's site) is your friend. When I work with creating documents with OpenXML, I do the following:
Create a document similar to what I want using Excel or Word (in this case, an Excel spreadsheet document with two sheets (I labeled them "First" and "Second")).
Open the document up in the productivity tool
Reflect the code (a button on the Tool's UI)
Copy/paste the code I want.
If I do that, I end up with all the code I need. I've boiled it down to the essentials to answer your question. Excel will complain that the document produced below is corrupt (since all it includes is the code to create the two sheets - and leaves lots of other required code out - all of which is stealable from the tool). However, if you tell Excel "Repair this for me", you will get a document with two sheets, labeled "First" and "Second"
WorkbookPart workbookPart1 = document.AddWorkbookPart();
Workbook workbook1 = new Workbook() { MCAttributes = new MarkupCompatibilityAttributes() { Ignorable = "x15 xr xr6 xr10 xr2" } };
//lots of namespace declarations - copy them from the tool (they are needed!!)
//lots of code for WorkbookProperties, etc (you can get this from Tool)
Sheets sheets1 = new Sheets();
Sheet sheet1 = new Sheet() { Name = "First", SheetId = (UInt32Value)1U, Id = "rId1" };
Sheet sheet2 = new Sheet() { Name = "Second", SheetId = (UInt32Value)2U, Id = "rId2" };
sheets1.Append(sheet1);
sheets1.Append(sheet2);
//More elided code
workbook1.Append(sheets1);
workbookPart1.Workbook = workbook1;
I strongly recommend that you keep the pluralization of things like Sheet and Sheets clear. Your code has Sheets sheetCol = new Sheets();, it's not clear after that that sheetCol is a Sheets and not a Sheet.
Then you have something called sheetToCreate which is a SheetData object. Again, that's confusing - call it something clear like thisSheetData or something. I really strongly recommend that you follow the OpenXML naming as much as you can, otherwise it is extremely hard to follow what's going on.
The Productivity Tool is also handy once you've written out your file. You can see what you created, often spotting what the error is. In addition, there's a validate button that usually (not always) points you to problems in the structure of your documents.
Good luck. Prepare to get better at cussing at your code!

VSTO Excel Read from Current Open Workbook

Is it possible to read from an open Excel (xlsx) using EPPlus? I want the user to be able to open an Excel document, click the Add-In button and read data from the active worksheet. I don't need to write to the worksheet, only read from it.
Using interop I was able to get the full path to the open workbook but when I tried to actually access the workbook I got an I/O error. Any ideas how to get around this?
var test = ( Microsoft.Office.Interop.Excel.Workbook ) Globals.ThisAddIn.Application.ActiveWorkbook;
var test2 = test.ActiveSheet;
//var test21 = ( Microsoft.Office.Interop.Excel.Workbook ) Globals.ThisAddIn.Application.ActiveSheet;
var test3 = new FileInfo( test.FullName );
using ( ExcelPackage package = new ExcelPackage( test3) ) // <--- I/O error here
{
var worksheet = package.Workbook.Worksheets[ "Sheet1" ];
string myString = String.Format( "{0}", worksheet.Cells[ 1, 1 ].Text );
}
Try non-exclusive access, like this:
....
var stream = new FileStream(test.FullName, FileMode.Open, FileAccess.Read,
FileShare.ReadWrite); // <<< ---!!
using (ExcelPackage package = new ExcelPackage(stream))
{
...
}

NPOI xls: calculated end index (x) is out of allowable range (y..y+2)

I always get an exception when writing to newly created file. I get this exception even if provided sheet is empty. Workbook without sheets saves without a problem.
This exception shows for an empty sheet.
Additional information: calculated end index (1932) is out of
allowable range (1908..1910)
I'm using NOPI.dll ver.2.1.3.1 http://npoi.codeplex.com/
File I try to create is .xls (Excel 97-2003)
filePath in code bolow has a value #"C:\TB\Report.xls"
My code
public void Generate()
{
HSSFWorkbook newWorkBook = new HSSFWorkbook();
ISheet newSheet = newWorkBook.CreateSheet("Main");
newWorkBook.Add(newSheet);
using (FileStream fileOut = new FileStream(filePath, FileMode.Create))
{
newWorkBook.Write(fileOut);
}
}
File is created but it's empty.
When creating xls with sheet that has rows and columns the result is the same except the numbers in exception are higher.
The problem was using ISheet instead of HSSFSheet. Example shown in the documentation used ISheet but it was incorrect.
Correct code:
public void Generate()
{
HSSFWorkbook newWorkBook = new HSSFWorkbook();
HSSFSheet newSheet = (HSSFSheet)newWorkBook.CreateSheet("Main");
var headerRow = newSheet.CreateRow(0);
var headerCell = headerRow.CreateCell(0);
headerCell.SetCellValue("Something");
using (FileStream fileOut = new FileStream(filePath, FileMode.Create))
{
newWorkBook.Write(fileOut);
}
}

The process cannot access the file because it is being used by another process using spreadsheet document

Please help me to solve the problem, when i save the excel file throw this error i convert the excel file to zip file.
zip.Save(#"" + root + "/" + "" + userid + ".zip");
the process cannot access the file because it is being used by another process
my code is below
using (SpreadsheetDocument document = SpreadsheetDocument.Create(excelFilename, SpreadsheetDocumentType.Workbook))
{
WriteExcelFile(ds, document);
}
private static void WriteExcelFile(DataSet ds, SpreadsheetDocument spreadsheet)
{
spreadsheet.AddWorkbookPart();
spreadsheet.WorkbookPart.Workbook = new DocumentFormat.OpenXml.Spreadsheet.Workbook();
spreadsheet.WorkbookPart.Workbook.Append(new BookViews(new WorkbookView()));
// If we don't add a "WorkbookStylesPart", OLEDB will refuse to connect to this .xlsx file !
WorkbookStylesPart workbookStylesPart = spreadsheet.WorkbookPart.AddNewPart<WorkbookStylesPart>("rIdStyles");
Stylesheet stylesheet = new Stylesheet();
workbookStylesPart.Stylesheet = stylesheet;
// Loop through each of the DataTables in our DataSet, and create a new Excel Worksheet for each.
uint worksheetNumber = 1;
foreach (DataTable dt in ds.Tables)
{
// For each worksheet you want to create
string workSheetID = "rId" + worksheetNumber.ToString();
string worksheetName = dt.TableName;
WorksheetPart newWorksheetPart = spreadsheet.WorkbookPart.AddNewPart<WorksheetPart>();
newWorksheetPart.Worksheet = new DocumentFormat.OpenXml.Spreadsheet.Worksheet();
// create sheet data
newWorksheetPart.Worksheet.AppendChild(new DocumentFormat.OpenXml.Spreadsheet.SheetData());
// save worksheet
WriteDataTableToExcelWorksheet(dt, newWorksheetPart);
newWorksheetPart.Worksheet.Save();
// create the worksheet to workbook relation
if (worksheetNumber == 1)
spreadsheet.WorkbookPart.Workbook.AppendChild(new DocumentFormat.OpenXml.Spreadsheet.Sheets());
spreadsheet.WorkbookPart.Workbook.GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.Sheets>().AppendChild(new DocumentFormat.OpenXml.Spreadsheet.Sheet()
{
Id = spreadsheet.WorkbookPart.GetIdOfPart(newWorksheetPart),
SheetId = (uint)worksheetNumber,
Name = dt.TableName
});
worksheetNumber++;
}
spreadsheet.WorkbookPart.Workbook.Save();
}
I see that you have saved your document but you have not closed it. So, it will still be open with the spreadsheetdocument object.
Add the following line after you save the document.
spreadsheet.WorkbookPart.Workbook.Close();
If it doesn't help, kindly provide the full code so that we can look into it further. Good luck.
I think you are not closing all your Workbooks before you try to put them in the Zip-File.
Put this at the end of the Method:
private static void WriteExcelFile(DataSet ds, SpreadsheetDocument spreadsheet)
{
...
spreadsheet.WorkbookPart.Workbook.Close();
}

Categories