Can is possibility create Excel document without placed inside spreedsheet the base table? Or at least that base table was in other worksheet than pivot table.
Currently I create DataColumn, after add row and...
ExcelWorksheet worksheet = pkg.Workbook.Worksheets.Add("Table");
worksheet.Cells["A1"].LoadFromDataTable(table, true);
var pivotTable = worksheet.PivotTables.Add(worksheet.Cells["H14"],
worksheet.Cells[rangePivotTable], "pivTable");
pivotTable.RowFields.Add(pivotTable.Fields["Grid"]);
.
.
.
It seems that EPPlus PivotTable can be created only from the data that is already present in the workbook; so you have to place source table into the spreadsheet.
Good news is that you can easily have pivot table and base table in the different worksheets:
var wsPvt = pkg.Workbook.Worksheets.Add( "Pivot Table" );
var wsData = pkg.Workbook.Worksheets.Add( "Source Data" );
var rangePivotTable = wsData.Cells["A1"].LoadFromDataTable( tbl, true );
var pivotTable = wsPvt.PivotTables.Add(
ws.Cells[1,1],
rangePivotTable, "pvtTable");
I assume that you don't want to place base table into spreadsheet because it is either rather big or just contain sensitive details. In this case you may aggregate base table with C# code (group it by columns that used for pivot table rows and columns) and use grouped result as base table for Excel Pivot Table. Aggregation may be simply performed with PivotData library -- let me know if you're interested in this way and need more explanations (I'm an author of this library).
Absolutely! Just set the data source of the pivot table using PivotTable.SourceData to specify a connection string.
https://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.pivottable.sourcedata.aspx
A little different way to do it, that works for me, is as follows:
var dataRange = rawDataWorksheet.Cells[rawDataWorksheet.Dimension.Address];
var pivotTable =
pivotTableWorksheet.PivotTables.Add(pivotTableWorksheet.Cells["A6"]
dataRange, "PivotTable");
"rawDataWorksheet" is the sheet that contains the source data; "pivotTableWorksheet" is the sheet on which you want to plop the PivotTable. In the code above, it starts at the intersection of column A (1) and row 6, but you could use another target cell, of course.
Related
There was a similar question, it didn't seem answered (maybe there's not an answer). How do you "update" an existing Excel Table (named range) from Closed XML. I know how to get the table info, and delete the existing data (see below)
var ws = wb.Worksheet(sheetName);
var table = ws.Table("data");
table.Clear();
then ?? I have a list called "listdata" per say, which matches the table headers exactly...
Do I need to loop through the table one at a time like this (which seems like a waste):
foreach (var item in listdata){table.InsertRowsBelow(1); ws.Cells(2,1).InsertData(item)}
I guess maybe it would be kinda simpler if you did something like this:
table.InsertRowsBelow(listdata.Count()); ws.Cells(2,1).InsertData(listdata);
Or is there a way to bulk load into "table" (similar to .AddRange(listdata) or .Union(listdata)). Currently, I just delete the entire sheet then recreate the sheet and paste the new table:
wb.Worksheets.Delete(sheetName);
var ws = wb.Worksheets.Add(sheetName);
ws.Cell(1, 1).InsertTable(listdata, "data", true);
As far as I know, the approach you discuss in your answer is the simplest one, i.e.
get a reference to the table
remove its data
insert your list.
InsertData acts as a bulk insert, it will take any IEnumerable collection and output that whole collection into the Excel spreadsheet starting at the selected cell.
So, for example, you can do this to populate a table from a list (where the first row of the worksheet is the table's header row):
private void PopulateTable(XLWorkbook wb, string workSheetName, string tableName, IEnumerable list)
{
var ws = wb.Worksheet(workSheetName);
var table = ws.Table(tableName);
ws.Cell(2, 1).InsertData(list);
}
Cell also has an InsertTable function that will insert a DataTable instead of an IEnumerable.
In https://github.com/ClosedXML/ClosedXML/pull/932 some additions have been made to IXLTable. You might be interested in IXLTable.ReplaceData(data) and IXLTable.AppendData(data).
I'm getting stuck trying to update the SourceRange of a Pivot-Table with EPPLus inside a C# class.
I've found that CacheDefinition.SourceRange contains the DataSource of my existing Pivot-Table but I don't know how to change it.
Existing Pivot-Table datasource is a range on a data worksheet in the same Excel file.
Any advice?
Thanks in advance,
Alessandro
This might work:
You can create a self-dimensioning defined name that encompasses your data range. I use this all the time.
Open Name Manager.
Click New.
Enter a Name for your range.
Put the following in the Refers to: line
OFFSET(DataSource!$A$1,0,0,COUNTA(DataSource!$A:$A),COUNTA(DataSource!$1:$1))
syntax: OFFSET(reference, rows, cols, [height], [width])
Substitute your sheet/tab name for DataSource. This assumes that the table starts in A1 (first section) and you that you want a defined name as long as the number of values in column A and as wide as the values in row 1. It is a very flexible and useful method for making sure your defined names encompass all the data on the sheet.
With ClosedXML I am trying to add data to an existing Excel Sheet In an Existing Table. The easy thing to do is to add a table to an excel sheet below is a quick example of how to do that. What I don't understand is if you already have a Table there that is empty how can you just add to the existing table?
// Add a DataTable as a worksheet
wb.Worksheets.Add(dataTable);
I don't know how this question isn't clear to people. If there is an existing Table (created in Excel by going to "Insert -> Table") and you open an Excel document using ClosedXML, adding data to the next row does not automatically expand the Table.
You can expand it prior to adding the data as such:
IXLTables tsTables = thisSheet.Tables;
IXLTable firstTable = tsTables.FirstOrDefault();
if (firstTable != null)
firstTable.InsertRowsBelow(1);
I had a similar requirement, where I needed to insert data into an existing Table, which had a number of data validations / comments / formula built in.
I found that the easiest solution (for me) was to use the Table's ReplaceData call. This is particularly useful if you provide a name for your Table in the Excel worksheet, as that way you can get a reference to the table directly from the workbook, ie:
var candidateTable = workbook.Table("Candidates");
candidateTable.ReplaceData(candidateData, propagateExtraColumns: true);
Note that the key to getting this to work properly is to set the propogateExtraColumns parameter - this will ensure any formula / etc you have set will automatically be copied to any new rows that are created.
FYI - you can set the Excel Table's name by selecting your table in the worksheet, clicking the Design tab, and then entering a table name:
To add a DataTable to an existing worksheet use this:
wb.Worksheet(1).Cell(1, 1).InsertTable(dataTable);
More info in the documentation.
I need to know how to get the count of cells in a Row object using OpenXML. Currently, I am using
row.Descendants<Cell>().Count<Cell>()
but this is not correct at all. Any ideas what method/property gives me the count of cells?
You can get the count using one of the followings:
row.Descendants<Cell>().Count<Cell>() //The one you used
row.Elements<Cell>().Count<Cell>()
row.Count()
I tested all of them and they are working correctly. Keep in mind the following points while validating the correctness of the returned count:
- Hidden columns are included in the calculations
- Merged cells are counted separately. If your excel sheet contains 3 columns A, B & C, but A & B are merged, then the count of the cells is 3 not 2
You can extract a list of all the merged cells in a sheet using:
SpreadsheetDocument ExcelSpreadSheet = SpreadsheetDocument.Open(ReportFile, true);
WorksheetPart ExcelWSP = GetWorksheetPartByName(ExcelSpreadSheet, TemplateEntity.ExcelSheetName);
MergeCells mergeList = ExcelWSP.Worksheet.Elements<MergeCells>().First();
The merge information is saved in the Reference property, and you can access it using the following:
((MergeCell)mergeList.ElementAt(i)).Reference
I am making an add-in and I am trying to format the output which my add-in generates,using Format as table table-styles provided by Excel.
The one which you get on the 'home tab' --> 'Format as Table' button on the ribbon.
I am using following code:
SourceRange.Worksheet.ListObjects.Add(XlListObjectSourceType.xlSrcRange,
SourceRange, System.Type.Missing, xlYesNo, System.Type.Missing).Name =
TableName;
SourceRange.Select();
SourceRange.Worksheet.ListObjects[TableName].TableStyle = TableStyleName;
TableStyleName is any style name like TableStyleMedium17, you get it if you just hover a particular style in Excel.
My problem is that, even if I keep the SourceRange as 10 columns, all the columns right till the end get selected and are considered as one table.
Because of that the table I populate right next to it is also considered as a part of the first table that was generated.Since, both the table have same column names excel automatically changes the column names in all the following tables that are generated.
Also, because I am generating the tables in a loop after 2 tables are generated I get the error :
A table cannot overlap another table.
PS: I am clearly mentioning SourceRange as:
var startCell = (Range)worksheet.Cells[startRow, startCol];
var endCell = (Range)worksheet.Cells[endRow, endCol];
var SourceRange = worksheet.get_Range(startCell, endCell);
Kindly suggest a way out.
We were able to figure out what was happening on our end for this:
on the
xlWorkbook.Worksheets.Add([before],[after], Type.Missing, Type.Missing)
call, we had to flip before and after since we wanted the sheets to move right, not left and then accessed
xlWorkbook.Worksheets[sheetCount]
by increasing sheetcount for however many sheets were being generated.
Having it the other way was creating the worksheet to access a previously assigned table formatfrom the SourceRange.Worksheet.ListObjects[TableName].TableStyle = TableStyleName call.
So, I got around this problem a week after posting this, sorry did not update in the rush of things.
This actually is an in built excel functionality.
You cant help it, the excel application will keep doing this.
So, ultimately wrote my own table styles in c# and applied it to the excel range which is mentioned as SourceRange. Its just like writing CSS.
If you are interested in knowing the details of that comment it on this question itself or you can contact me by email from my profile.