Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
245 views
in Technique[技术] by (71.8m points)

c# - Create Pivot Table Filters With EPPLUS

I am using EPPLUS excel library. Do you have an idea how to create pivot table with report filters, row label and values ? Some simple example will be excellent.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here is a simple example. Note that EEPlus does not have the ability to do page filters so you will have to use (in order of difficulty) VBA, Excel Interop, or XML manipulation (I used XML below). You can put this code into a unit test of the EPPlus source download for easy testing:

const string FORMATCURRENCY = "#,###;[Red](#,###)";

var file = new FileInfo(@"c:empemp.xlsx");
if (file.Exists)
    file.Delete();

var pck = new ExcelPackage(file);
var workbook = pck.Workbook;
var worksheet = workbook.Worksheets.Add("newsheet");

//The data
worksheet.Cells["A20"].Value = "Col1";
worksheet.Cells["A21"].Value = "sdf";
worksheet.Cells["A22"].Value = "wer";
worksheet.Cells["A23"].Value = "ghgh";
worksheet.Cells["A24"].Value = "sdf";
worksheet.Cells["A25"].Value = "wer";
worksheet.Cells["A26"].Value = "ghgh";
worksheet.Cells["A27"].Value = "sdf";
worksheet.Cells["A28"].Value = "wer";
worksheet.Cells["A29"].Value = "ghgh";

worksheet.Cells["B20"].Value = "Col2";
worksheet.Cells["B21"].Value = "Group A";
worksheet.Cells["B22"].Value = "Group B";
worksheet.Cells["B23"].Value = "Group A";
worksheet.Cells["B24"].Value = "Group C";
worksheet.Cells["B25"].Value = "Group A";
worksheet.Cells["B26"].Value = "Group B";
worksheet.Cells["B27"].Value = "Group C";
worksheet.Cells["B28"].Value = "Group C";
worksheet.Cells["B29"].Value = "Group A";

worksheet.Cells["C20"].Value = "Col3";
worksheet.Cells["C21"].Value = 453;
worksheet.Cells["C22"].Value = 634;
worksheet.Cells["C23"].Value = 274;
worksheet.Cells["C24"].Value = 453;
worksheet.Cells["C25"].Value = 634;
worksheet.Cells["C26"].Value = 274;
worksheet.Cells["C27"].Value = 453;
worksheet.Cells["C28"].Value = 634;
worksheet.Cells["C29"].Value = 274;

worksheet.Cells["D20"].Value = "Col4";
worksheet.Cells["D21"].Value = 686468;
worksheet.Cells["D22"].Value = 996440;
worksheet.Cells["D23"].Value = 185780;
worksheet.Cells["D24"].Value = 686468;
worksheet.Cells["D25"].Value = 996440;
worksheet.Cells["D26"].Value = 185780;
worksheet.Cells["D27"].Value = 686468;
worksheet.Cells["D28"].Value = 996440;
worksheet.Cells["D29"].Value = 185780;

//The pivot table
var pivotTable = worksheet.PivotTables.Add(worksheet.Cells["A4"], worksheet.Cells["A20:D29"], "test");

//The label row field
pivotTable.RowFields.Add(pivotTable.Fields["Col1"]);
pivotTable.DataOnRows = false;

//The data fields
var field = pivotTable.DataFields.Add(pivotTable.Fields["Col3"]);
field.Name = "Sum of Col2";
field.Function = DataFieldFunctions.Sum;
field.Format = FORMATCURRENCY;

field = pivotTable.DataFields.Add(pivotTable.Fields["Col4"]);
field.Name = "Sum of Col3";
field.Function = DataFieldFunctions.Sum;
field.Format = FORMATCURRENCY;

//The page field
pivotTable.PageFields.Add(pivotTable.Fields["Col2"]);
var xdCacheDefinition = pivotTable.CacheDefinition.CacheDefinitionXml;
var xeCacheFields = xdCacheDefinition.FirstChild["cacheFields"];
if (xeCacheFields == null)
    return;

//To filter, add items to the Cache Definition via XML
var count = 0;
var assetfieldidx = -1;

foreach (XmlElement cField in xeCacheFields)
{
    var att = cField.Attributes["name"];
    if (att != null && att.Value == "Col2" )
    {
        assetfieldidx = count;

        var sharedItems = cField.GetElementsByTagName("sharedItems")[0] as XmlElement;
        if(sharedItems == null)
            continue;

        //set the collection attributes
        sharedItems.RemoveAllAttributes();
        att = xdCacheDefinition.CreateAttribute("count");
        att.Value = "3";
        sharedItems.Attributes.Append(att);

        //create and add the item
        var item = xdCacheDefinition.CreateElement("s", sharedItems.NamespaceURI);
        att = xdCacheDefinition.CreateAttribute("v");
        att.Value = "Group A";
        item.Attributes.Append(att);
        sharedItems.AppendChild(item);

        item = xdCacheDefinition.CreateElement("s", sharedItems.NamespaceURI);
        att = xdCacheDefinition.CreateAttribute("v");
        att.Value = "Group B";
        item.Attributes.Append(att);
        sharedItems.AppendChild(item);

        item = xdCacheDefinition.CreateElement("s", sharedItems.NamespaceURI);
        att = xdCacheDefinition.CreateAttribute("v");
        att.Value = "Group C";
        item.Attributes.Append(att);
        sharedItems.AppendChild(item);

        break;
    }

    count++;
}

//Now go back to the main pivot table xml and add the cross references to complete filtering
var xdPivotTable = pivotTable.PivotTableXml;
var xdPivotFields = xdPivotTable.FirstChild["pivotFields"];
if (xdPivotFields == null)
    return;

count = 0;
foreach (XmlElement pField in xdPivotFields)
{
    //Find the asset type field
    if (count == assetfieldidx)
    {
        var att = xdPivotTable.CreateAttribute("multipleItemSelectionAllowed");
        att.Value = "1";
        pField.Attributes.Append(att);

        var items = pField.GetElementsByTagName("items")[0] as XmlElement;
        items.RemoveAll();

        att = xdPivotTable.CreateAttribute("count");
        att.Value = "4";
        items.Attributes.Append(att);
        pField.AppendChild(items);

        //Add the classes to the fields item collection
        for (var i = 0; i < 3; i++)
        {
            var item = xdPivotTable.CreateElement("item", items.NamespaceURI);
            att = xdPivotTable.CreateAttribute("x");
            att.Value = i.ToString(CultureInfo.InvariantCulture);
            item.Attributes.Append(att);

            //Turn of the Cash class in the fielder
            if (i == 1)
            {
                att = xdPivotTable.CreateAttribute("h");
                att.Value = "1";
                item.Attributes.Append(att);
            }

            items.AppendChild(item);

        }

        //Add the default
        var defaultitem = xdPivotTable.CreateElement("item", items.NamespaceURI);
        att = xdPivotTable.CreateAttribute("t");
        att.Value = "default";
        defaultitem.Attributes.Append(att);
        items.AppendChild(defaultitem);

        break;
    }
    count++;
}

pck.Save();

Sorry for all the edit but I have been working on this for a little while when I stumbled on this question. I created an extension method just for applying a filter. Give it the field name (it assumes there is a header line contining the column names), the filters you want to apply, and the worksheet containing the data or it will just the Pivot Table worksheet if no data worksheet is passed in. It have done basic testing so you should QA:

public static bool FilterField(this ExcelPivotTable pivotTable, string pageFieldName, IEnumerable<object> filters, ExcelWorksheet dataWorksheet = null)
{
    //set the worksheet
    var ws = dataWorksheet ?? pivotTable.WorkSheet;

    //Set the cache definitions and cache fields
    var xdCacheDefinition = pivotTable.CacheDefinition.CacheDefinitionXml;
    var xeCacheFields = xdCacheDefinition.FirstChild["cacheFields"];
    if (xeCacheFields == null)
        return false;

    //Go the field list in the definitions, note the field idx and valuesfor 
    var count = 0;
    var fieldIndex = -1;
    List<object> fieldValues = null;

    foreach (XmlElement cField in xeCacheFields)
    {
        var att = cField.Attributes["name"];
        if (att != null && att.Value.Equals(pageFieldName, StringComparison.OrdinalIgnoreCase))
        {
            //store the field data
            fieldIndex = count;
            var dataddress = new ExcelAddress(pivotTable.CacheDefinition.SourceRange.Address);

            var valueHeader = ws
                .Cells[dataddress.Start.Row, dataddress.Start.Column, dataddress.Start.Row, dataddress.End.Column]
                .FirstOrDefault(cell => cell.Value.ToString().Equals(pageFieldName, StringComparison.OrdinalIgnoreCase));

            if (valueHeader == null)
                return false;

            //Get the range minus the header row
            var valueObject = valueHeader.Offset(1, 0, dataddress.End.Row - dataddress.Start.Row, 1).Value;
            var values = (object[,])valueObject;

            fieldValues = values
                .Cast<object>()
                .Distinct()
                .ToList();

            //kick back if the types are mixed
            if (fieldValues.FirstOrDefault(v => v is string) != null && fieldValues.FirstOrDefault(v => !(v is string)) != null)
                throw new NotImplementedException("Filter function does not (yet) support mixed parameter types");

            //fill in the shared items for the field
            var sharedItems = cField.GetElementsByTagName("sharedItems")[0] as XmlElement;
            if (sharedItems == null)
                continue;

            //Reset the collection attributes
            sharedItems.RemoveAllAttributes();

            //Handle numerics - assume all or nothing
            var isNumeric = fieldValues.FirstOrDefault(v => v is string) == null;
            if (isNumeric)
            {
                att = xdCacheDefinition.CreateAttribute("containsSemiMixedTypes");
                att.Value = "0";
                sharedItems.Attributes.Append(att);

                att = xdCacheDefinition.CreateAttribute("containsString");
                att.Value = "0";
                sharedItems.Attributes.Append(att);

                att = xdCacheDefinition.CreateAttribute("containsNumber");
                att.Value = "1";
                sharedItems.Attributes.Append(att);

                att = xdCacheDefinition.CreateAttribute("containsInteger");
                att.Value = fieldValues.Any(v => !(v is int || v is long)) ? "0" : "1";
                sharedItems.Attributes.Append(att);
            }

            //add the count
            att = xdCacheDefinition.CreateAttribute("count");
            att.Value = fieldValues.Count.ToString(CultureInfo.InvariantCulture);
            sharedItems.Attributes.Append(att);

            //create and add the item
            foreach (var fieldvalue in fieldValues)
            {
                var item = xdCacheDefinition.CreateElement(isNumeric ? "n" : "s", sharedItems.NamespaceURI);
                att = xdCacheDefinition.CreateAttribute("v");
                att.Value = fieldvalue.ToString();
                item.Attributes.Append(att);
                sharedItems.AppendChild(item);
            }

            break;
        }

        count++;
    }

    if (fieldIndex == -1 || fieldValues == null)
        return false;

    //Now go back to the main pivot table xml and add the cross references to complete filtering
    var xdPivotTable = pivotTable.PivotTableXml;
    var xdPivotFields = xdPivotTable.FirstChild["pivotFields"];
    if (xdPivotFields == null)
        return false;

    var filtervalues = filters.ToList();
    count = 0;
    foreach (XmlElement pField in xdPivotFields)
    {
        //Find the asset type field
        if (count == fieldIndex)
        {
            var att = xdPivotTable.CreateAttribute("multipleItemSelectionAllowed");
            att.Value = "1";
            pField.Attributes.Append(att);

            var items = pField.GetElementsByTagName("items")[0] as XmlElement;
            if (items == null)
                return false;

            items.RemoveAll();

            att = xdPivotTable.CreateAttribute("count");
            att.Value = (fieldValues.Count + 1).ToString(CultureInfo.InvariantCulture);
            items.Attributes.Append(att);
            pField.AppendChild(items);

            //Add the classes to the fields item collection
            for (var i = 0; 

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...