I am porting Excel Interop PivotTable code to EPPlus. I'm at a sticking point in generating a calculated field value. In Excel Interop I can do it this way:
pvt.AddDataField(pvt.PivotFields("TotalQty"), "Total Packages", XlConsolidationFunction.xlSum).NumberFormat = "###,##0";
pvt.AddDataField(pvt.PivotFields("TotalPrice"), "Total Purchases", XlConsolidationFunction.xlSum).NumberFormat = "$#,##0.00";
PivotField avg = pvt.CalculatedFields().Add("Average Price", "=TotalPrice/TotalQty", true);
avg.Orientation = XlPivotFieldOrientation.xlDataField;
avg.NumberFormat = "$###0.00";
With this the "Average Price" value on the PivotTable displays the value for TotalPrice divided by TotalQty.
But how to do it in EPPlus? I can create the "plain vanilla" data fields like so:
var totQtyField = pivotTable.Fields["TotalQty"];
pivotTable.DataFields.Add(totQtyField);
var totPriceField = pivotTable.Fields["TotalPrice"];
pivotTable.DataFields.Add(totPriceField);
...but when it comes to calculating a value, I'm baffled. My starting point was an online example for sums like so:
pivotTable.DataFields.Add(pivotTable.Fields["AvgPrice"]).Function =
OfficeOpenXml.Table.PivotTable.DataFieldFunctions.Sum();
So I tried the following, but none of them is right:
pivotTable.DataFields.Add(pivotTable.Fields["AvgPrice"]).Function =
OfficeOpenXml.Table.PivotTable.DataFieldFunctions.Average(totPriceField, totQtyField);
pivotTable.DataFields.Add(pivotTable.Fields["AvgPrice"]).Function = "TotalPrice/TotalQty";
pivotTable.DataFields.Add(pivotTable.Fields["AvgPrice"]) = "TotalPrice/TotalQty";
pivotTable.DataFields.Add(pivotTable.Fields["AvgPrice"]) = totPriceField / totQtyField;
pivotTable.DataFields.Add(pivotTable.Fields["AvgPrice"]).Function =
OfficeOpenXml.Table.PivotTable.
DataFieldFunctions.Product(totPriceField/totQtyField);
None of those flailings even compile. What adjustment do I need to make, or what completely new approach do I need to take?
UPDATE
I could calculate the values and put them on the data sheet and reference it that way; but is this really the only/best way to do this?
UPDATE 2
I did that (added the vals directly to the sheet that contains the source data for the Pivot Table):
var avgCell = rawDataWorksheet.Cells[_lastRowAddedRawData + 1, 9];
if ((TotalPrice < 0.0M) || (Quantity < 1))
{
avgCell.Value = 0.0;
}
else
{
avgCell.Value = TotalPrice / Quantity;
}
var prcntgCell = rawDataWorksheet.Cells[_lastRowAddedRawData + 1, 10];
if ((TotalPrice < 0.0M) || (MonthYear == String.Empty))
{
prcntgCell.Value = 0.0;
}
else
{
prcntgCell.Value = GetPercentageOfItemForMonthYear(TotalPrice, MonthYear);
}
private double GetPercentageOfItemForMonthYear(decimal totPrice, strin
monthYear)
{
decimal totalForMonthYear = monthlySales[monthYear];
double prcntg = GetPercentageOfItem(totPrice, totalForMonthYear);
return prcntg;
}
private double GetPercentageOfItem(decimal portionOfTotal, decimal
grandTotal)
{
if ((portionOfTotal <= 0.0M) || (grandTotal <= 0.0M))
{
return 0.0;
}
if (portionOfTotal == grandTotal)
{
return 100.0;
}
double d = Convert.ToDouble(portionOfTotal)
/ Convert.ToDouble(grandTotal) * 100;
return Math.Round(d, 2);
}
...but still would like to know how that's accomplishable using calculated fields while the PivotTable is being created.