|  | /******************************************************************************* | 
|  | * You may amend and distribute as you like, but don't remove this header! | 
|  | * | 
|  | * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. | 
|  | * See http://www.codeplex.com/EPPlus for details. | 
|  | * | 
|  | * Copyright (C) 2011  Jan Källman | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  |  | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 
|  | * See the GNU Lesser General Public License for more details. | 
|  | * | 
|  | * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php | 
|  | * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html | 
|  | * | 
|  | * All code and executables are provided "as is" with no warranty either express or implied. | 
|  | * The author accepts no liability for any damage or loss of business that this product may cause. | 
|  | * | 
|  | * Code change notes: | 
|  | * | 
|  | * Author							Change						Date | 
|  | * ****************************************************************************** | 
|  | * Jan Källman		Added		21-MAR-2011 | 
|  | * Jan Källman		License changed GPL-->LGPL 2011-12-16 | 
|  | *******************************************************************************/ | 
|  |  | 
|  | using System; | 
|  | using System.Collections.Immutable; | 
|  | using System.Text.RegularExpressions; | 
|  | using System.Xml; | 
|  | using OfficeOpenXml.Packaging; | 
|  | using OfficeOpenXml.Utils; | 
|  |  | 
|  | namespace OfficeOpenXml.Table.PivotTable; | 
|  |  | 
|  | /// <summary> | 
|  | /// An Excel Pivottable | 
|  | /// </summary> | 
|  | public class ExcelPivotTable : XmlHelper { | 
|  | protected override ImmutableArray<string> SchemaNodeOrder { get; } = [ | 
|  | "location", | 
|  | "pivotFields", | 
|  | "rowFields", | 
|  | "rowItems", | 
|  | "colFields", | 
|  | "colItems", | 
|  | "pageFields", | 
|  | "pageItems", | 
|  | "dataFields", | 
|  | "dataItems", | 
|  | "formats", | 
|  | "pivotTableStyleInfo", | 
|  | ]; | 
|  |  | 
|  | internal ExcelPivotTable(ZipPackageRelationship rel, ExcelWorksheet sheet) | 
|  | : base(sheet.NameSpaceManager) { | 
|  | WorkSheet = sheet; | 
|  | PivotTableUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri); | 
|  | Relationship = rel; | 
|  | var package = sheet._package; | 
|  | PivotTableXml = package.GetXmlDocument(PivotTableUri); | 
|  | TopNode = PivotTableXml.DocumentElement; | 
|  | Address = new(GetXmlNodeString("d:location/@ref")); | 
|  |  | 
|  | CacheDefinition = new(sheet.NameSpaceManager, this); | 
|  | LoadFields(); | 
|  |  | 
|  | //Add row fields. | 
|  | foreach (XmlElement rowElem in TopNode.SelectNodes("d:rowFields/d:field", NameSpaceManager)) { | 
|  | if (int.TryParse(rowElem.GetAttribute("x"), out var x) && x >= 0) { | 
|  | RowFields.AddInternal(Fields[x]); | 
|  | } else { | 
|  | rowElem.ParentNode.RemoveChild(rowElem); | 
|  | } | 
|  | } | 
|  |  | 
|  | ////Add column fields. | 
|  | foreach (XmlElement colElem in TopNode.SelectNodes("d:colFields/d:field", NameSpaceManager)) { | 
|  | if (int.TryParse(colElem.GetAttribute("x"), out var x) && x >= 0) { | 
|  | ColumnFields.AddInternal(Fields[x]); | 
|  | } else { | 
|  | colElem.ParentNode.RemoveChild(colElem); | 
|  | } | 
|  | } | 
|  |  | 
|  | //Add Page elements | 
|  | //int index = 0; | 
|  | foreach (XmlElement pageElem in TopNode.SelectNodes( | 
|  | "d:pageFields/d:pageField", | 
|  | NameSpaceManager)) { | 
|  | if (int.TryParse(pageElem.GetAttribute("fld"), out var fld) && fld >= 0) { | 
|  | var field = Fields[fld]; | 
|  | field._pageFieldSettings = new(NameSpaceManager, pageElem, field, fld); | 
|  | PageFields.AddInternal(field); | 
|  | } | 
|  | } | 
|  |  | 
|  | //Add data elements | 
|  | //index = 0; | 
|  | foreach (XmlElement dataElem in TopNode.SelectNodes( | 
|  | "d:dataFields/d:dataField", | 
|  | NameSpaceManager)) { | 
|  | if (int.TryParse(dataElem.GetAttribute("fld"), out var fld) && fld >= 0) { | 
|  | var field = Fields[fld]; | 
|  | var dataField = new ExcelPivotTableDataField(NameSpaceManager, dataElem, field); | 
|  | DataFields.AddInternal(dataField); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | private void LoadFields() { | 
|  | //Fields.Clear(); | 
|  | //int ix=0; | 
|  | //foreach(XmlElement fieldNode in PivotXml.SelectNodes("//d:pivotFields/d:pivotField",NameSpaceManager)) | 
|  | //{ | 
|  | //    Fields.AddInternal(new ExcelPivotTableField(NameSpaceManager, fieldNode, this, ix++)); | 
|  | //} | 
|  |  | 
|  | int index = 0; | 
|  | //Add fields. | 
|  | foreach (XmlElement fieldElem in TopNode.SelectNodes( | 
|  | "d:pivotFields/d:pivotField", | 
|  | NameSpaceManager)) { | 
|  | var fld = new ExcelPivotTableField(NameSpaceManager, fieldElem, this, index, index++); | 
|  | Fields.AddInternal(fld); | 
|  | } | 
|  |  | 
|  | //Add fields. | 
|  | index = 0; | 
|  | foreach (XmlElement fieldElem in CacheDefinition.TopNode.SelectNodes( | 
|  | "d:cacheFields/d:cacheField", | 
|  | NameSpaceManager)) { | 
|  | var fld = Fields[index++]; | 
|  | fld.SetCacheFieldNode(fieldElem); | 
|  | } | 
|  | } | 
|  |  | 
|  | private XmlDocument GetStartXml( | 
|  | string name, | 
|  | int id, | 
|  | ExcelAddressBase address, | 
|  | ExcelAddressBase sourceAddress) { | 
|  | string xml = $""" | 
|  | <pivotTableDefinition xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" name=" | 
|  | {name}" cacheId="{id | 
|  | }" dataOnRows="1" applyNumberFormats="0" applyBorderFormats="0" applyFontFormats="0" applyPatternFormats="0" applyAlignmentFormats="0" applyWidthHeightFormats="1" dataCaption="Data"  createdVersion="4" showMemberPropertyTips="0" useAutoFormatting="1" itemPrintTitles="1" indent="0" compact="0" compactData="0" gridDropZones="1"> | 
|  |  | 
|  | """; | 
|  | xml += | 
|  | $"""<location ref="{address.FirstAddress | 
|  | }" firstHeaderRow="1" firstDataRow="1" firstDataCol="1" />"""; | 
|  | xml += $"""<pivotFields count="{sourceAddress._toCol - sourceAddress._fromCol + 1}">"""; | 
|  | for (int col = sourceAddress._fromCol; col <= sourceAddress._toCol; col++) { | 
|  | xml += """<pivotField showAll="0" />"""; | 
|  | } | 
|  | xml += "</pivotFields>"; | 
|  | xml += | 
|  | """<pivotTableStyleInfo name="PivotStyleMedium9" showRowHeaders="1" showColHeaders="1" showRowStripes="0" showColStripes="0" showLastColumn="1" />"""; | 
|  | xml += "</pivotTableDefinition>"; | 
|  | var result = new XmlDocument(); | 
|  | result.LoadXml(xml); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | internal ZipPackagePart Part { get; } | 
|  |  | 
|  | /// <summary> | 
|  | /// Provides access to the XML data representing the pivottable in the package. | 
|  | /// </summary> | 
|  | public XmlDocument PivotTableXml { get; private set; } | 
|  |  | 
|  | /// <summary> | 
|  | /// The package internal URI to the pivottable Xml Document. | 
|  | /// </summary> | 
|  | public Uri PivotTableUri { get; internal set; } | 
|  |  | 
|  | internal ZipPackageRelationship Relationship { get; set; } | 
|  |  | 
|  | //const string ID_PATH = "@id"; | 
|  | //internal int Id | 
|  | //{ | 
|  | //    get | 
|  | //    { | 
|  | //        return GetXmlNodeInt(ID_PATH); | 
|  | //    } | 
|  | //    set | 
|  | //    { | 
|  | //        SetXmlNodeString(ID_PATH, value.ToString()); | 
|  | //    } | 
|  | //} | 
|  | private const string _namePath = "@name"; | 
|  | private const string _displayNamePath = "@displayName"; | 
|  |  | 
|  | /// <summary> | 
|  | /// Name of the pivottable object in Excel | 
|  | /// </summary> | 
|  | public string Name { | 
|  | get => GetXmlNodeString(_namePath); | 
|  | set { | 
|  | if (WorkSheet.Workbook.ExistsTableName(value)) { | 
|  | throw (new ArgumentException("PivotTable name is not unique")); | 
|  | } | 
|  | string prevName = Name; | 
|  | if (WorkSheet.Tables._tableNames.ContainsKey(prevName)) { | 
|  | int ix = WorkSheet.Tables._tableNames[prevName]; | 
|  | WorkSheet.Tables._tableNames.Remove(prevName); | 
|  | WorkSheet.Tables._tableNames.Add(value, ix); | 
|  | } | 
|  | SetXmlNodeString(_namePath, value); | 
|  | SetXmlNodeString(_displayNamePath, CleanDisplayName(value)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Reference to the pivot table cache definition object | 
|  | /// </summary> | 
|  | public ExcelPivotCacheDefinition CacheDefinition { get; } | 
|  |  | 
|  | private string CleanDisplayName(string name) { | 
|  | return Regex.Replace(name, @"[^\w\.-_]", "_"); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// The worksheet where the pivottable is located | 
|  | /// </summary> | 
|  | public ExcelWorksheet WorkSheet { get; set; } | 
|  |  | 
|  | /// <summary> | 
|  | /// The location of the pivot table | 
|  | /// </summary> | 
|  | public ExcelAddressBase Address { get; internal set; } | 
|  |  | 
|  | /// <summary> | 
|  | /// If multiple datafields are displayed in the row area or the column area | 
|  | /// </summary> | 
|  | public bool DataOnRows { | 
|  | get => GetXmlNodeBool("@dataOnRows"); | 
|  | set => SetXmlNodeBool("@dataOnRows", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// if true apply legacy table autoformat number format properties. | 
|  | /// </summary> | 
|  | public bool ApplyNumberFormats { | 
|  | get => GetXmlNodeBool("@applyNumberFormats"); | 
|  | set => SetXmlNodeBool("@applyNumberFormats", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// If true apply legacy table autoformat border properties | 
|  | /// </summary> | 
|  | public bool ApplyBorderFormats { | 
|  | get => GetXmlNodeBool("@applyBorderFormats"); | 
|  | set => SetXmlNodeBool("@applyBorderFormats", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// If true apply legacy table autoformat font properties | 
|  | /// </summary> | 
|  | public bool ApplyFontFormats { | 
|  | get => GetXmlNodeBool("@applyFontFormats"); | 
|  | set => SetXmlNodeBool("@applyFontFormats", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// If true apply legacy table autoformat pattern properties | 
|  | /// </summary> | 
|  | public bool ApplyPatternFormats { | 
|  | get => GetXmlNodeBool("@applyPatternFormats"); | 
|  | set => SetXmlNodeBool("@applyPatternFormats", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// If true apply legacy table autoformat width/height properties. | 
|  | /// </summary> | 
|  | public bool ApplyWidthHeightFormats { | 
|  | get => GetXmlNodeBool("@applyWidthHeightFormats"); | 
|  | set => SetXmlNodeBool("@applyWidthHeightFormats", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Show member property information | 
|  | /// </summary> | 
|  | public bool ShowMemberPropertyTips { | 
|  | get => GetXmlNodeBool("@showMemberPropertyTips"); | 
|  | set => SetXmlNodeBool("@showMemberPropertyTips", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Show the drill indicators | 
|  | /// </summary> | 
|  | public bool ShowCalcMember { | 
|  | get => GetXmlNodeBool("@showCalcMbrs"); | 
|  | set => SetXmlNodeBool("@showCalcMbrs", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// If the user is prevented from drilling down on a PivotItem or aggregate value | 
|  | /// </summary> | 
|  | public bool EnableDrill { | 
|  | get => GetXmlNodeBool("@enableDrill", true); | 
|  | set => SetXmlNodeBool("@enableDrill", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Show the drill down buttons | 
|  | /// </summary> | 
|  | public bool ShowDrill { | 
|  | get => GetXmlNodeBool("@showDrill", true); | 
|  | set => SetXmlNodeBool("@showDrill", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// If the tooltips should be displayed for PivotTable data cells. | 
|  | /// </summary> | 
|  | public bool ShowDataTips { | 
|  | get => GetXmlNodeBool("@showDataTips", true); | 
|  | set => SetXmlNodeBool("@showDataTips", value, true); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// If the row and column titles from the PivotTable should be printed. | 
|  | /// </summary> | 
|  | public bool FieldPrintTitles { | 
|  | get => GetXmlNodeBool("@fieldPrintTitles"); | 
|  | set => SetXmlNodeBool("@fieldPrintTitles", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// If the row and column titles from the PivotTable should be printed. | 
|  | /// </summary> | 
|  | public bool ItemPrintTitles { | 
|  | get => GetXmlNodeBool("@itemPrintTitles"); | 
|  | set => SetXmlNodeBool("@itemPrintTitles", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// If the grand totals should be displayed for the PivotTable columns | 
|  | /// </summary> | 
|  | public bool ColumGrandTotals { | 
|  | get => GetXmlNodeBool("@colGrandTotals"); | 
|  | set => SetXmlNodeBool("@colGrandTotals", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// If the grand totals should be displayed for the PivotTable rows | 
|  | /// </summary> | 
|  | public bool RowGrandTotals { | 
|  | get => GetXmlNodeBool("@rowGrandTotals"); | 
|  | set => SetXmlNodeBool("@rowGrandTotals", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// If the drill indicators expand collapse buttons should be printed. | 
|  | /// </summary> | 
|  | public bool PrintDrill { | 
|  | get => GetXmlNodeBool("@printDrill"); | 
|  | set => SetXmlNodeBool("@printDrill", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Indicates whether to show error messages in cells. | 
|  | /// </summary> | 
|  | public bool ShowError { | 
|  | get => GetXmlNodeBool("@showError"); | 
|  | set => SetXmlNodeBool("@showError", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// The string to be displayed in cells that contain errors. | 
|  | /// </summary> | 
|  | public string ErrorCaption { | 
|  | get => GetXmlNodeString("@errorCaption"); | 
|  | set => SetXmlNodeString("@errorCaption", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Specifies the name of the value area field header in the PivotTable. | 
|  | /// This caption is shown when the PivotTable when two or more fields are in the values area. | 
|  | /// </summary> | 
|  | public string DataCaption { | 
|  | get => GetXmlNodeString("@dataCaption"); | 
|  | set => SetXmlNodeString("@dataCaption", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Show field headers | 
|  | /// </summary> | 
|  | public bool ShowHeaders { | 
|  | get => GetXmlNodeBool("@showHeaders"); | 
|  | set => SetXmlNodeBool("@showHeaders", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// The number of page fields to display before starting another row or column | 
|  | /// </summary> | 
|  | public int PageWrap { | 
|  | get => GetXmlNodeInt("@pageWrap"); | 
|  | set { | 
|  | if (value < 0) { | 
|  | throw new("Value can't be negative"); | 
|  | } | 
|  | SetXmlNodeString("@pageWrap", value.ToString()); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// A boolean that indicates whether legacy auto formatting has been applied to the PivotTable view | 
|  | /// </summary> | 
|  | public bool UseAutoFormatting { | 
|  | get => GetXmlNodeBool("@useAutoFormatting"); | 
|  | set => SetXmlNodeBool("@useAutoFormatting", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// A boolean that indicates whether the in-grid drop zones should be displayed at runtime, and whether classic layout is applied | 
|  | /// </summary> | 
|  | public bool GridDropZones { | 
|  | get => GetXmlNodeBool("@gridDropZones"); | 
|  | set => SetXmlNodeBool("@gridDropZones", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Specifies the indentation increment for compact axis and can be used to set the Report Layout to Compact Form | 
|  | /// </summary> | 
|  | public int Indent { | 
|  | get => GetXmlNodeInt("@indent"); | 
|  | set => SetXmlNodeString("@indent", value.ToString()); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// A boolean that indicates whether data fields in the PivotTable should be displayed in outline form | 
|  | /// </summary> | 
|  | public bool OutlineData { | 
|  | get => GetXmlNodeBool("@outlineData"); | 
|  | set => SetXmlNodeBool("@outlineData", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// a boolean that indicates whether new fields should have their outline flag set to true | 
|  | /// </summary> | 
|  | public bool Outline { | 
|  | get => GetXmlNodeBool("@outline"); | 
|  | set => SetXmlNodeBool("@outline", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// A boolean that indicates whether the fields of a PivotTable can have multiple filters set on them | 
|  | /// </summary> | 
|  | public bool MultipleFieldFilters { | 
|  | get => GetXmlNodeBool("@multipleFieldFilters"); | 
|  | set => SetXmlNodeBool("@multipleFieldFilters", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// A boolean that indicates whether new fields should have their compact flag set to true | 
|  | /// </summary> | 
|  | public bool Compact { | 
|  | get => GetXmlNodeBool("@compact"); | 
|  | set => SetXmlNodeBool("@compact", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// A boolean that indicates whether the field next to the data field in the PivotTable should be displayed in the same column of the spreadsheet | 
|  | /// </summary> | 
|  | public bool CompactData { | 
|  | get => GetXmlNodeBool("@compactData"); | 
|  | set => SetXmlNodeBool("@compactData", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Specifies the string to be displayed for grand totals. | 
|  | /// </summary> | 
|  | public string GrandTotalCaption { | 
|  | get => GetXmlNodeString("@grandTotalCaption"); | 
|  | set => SetXmlNodeString("@grandTotalCaption", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Specifies the string to be displayed in row header in compact mode. | 
|  | /// </summary> | 
|  | public string RowHeaderCaption { | 
|  | get => GetXmlNodeString("@rowHeaderCaption"); | 
|  | set => SetXmlNodeString("@rowHeaderCaption", value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Specifies the string to be displayed in cells with no value | 
|  | /// </summary> | 
|  | public string MissingCaption { | 
|  | get => GetXmlNodeString("@missingCaption"); | 
|  | set => SetXmlNodeString("@missingCaption", value); | 
|  | } | 
|  |  | 
|  | private const string _firstheaderrowPath = "d:location/@firstHeaderRow"; | 
|  |  | 
|  | /// <summary> | 
|  | /// Specifies the first row of the PivotTable header, relative to the top left cell in the ref value | 
|  | /// </summary> | 
|  | public int FirstHeaderRow { | 
|  | get => GetXmlNodeInt(_firstheaderrowPath); | 
|  | set => SetXmlNodeString(_firstheaderrowPath, value.ToString()); | 
|  | } | 
|  |  | 
|  | private const string _firstdatarowPath = "d:location/@firstDataRow"; | 
|  |  | 
|  | /// <summary> | 
|  | /// Specifies the first column of the PivotTable data, relative to the top left cell in the ref value | 
|  | /// </summary> | 
|  | public int FirstDataRow { | 
|  | get => GetXmlNodeInt(_firstdatarowPath); | 
|  | set => SetXmlNodeString(_firstdatarowPath, value.ToString()); | 
|  | } | 
|  |  | 
|  | private const string _firstdatacolPath = "d:location/@firstDataCol"; | 
|  |  | 
|  | /// <summary> | 
|  | /// Specifies the first column of the PivotTable data, relative to the top left cell in the ref value | 
|  | /// </summary> | 
|  | public int FirstDataCol { | 
|  | get => GetXmlNodeInt(_firstdatacolPath); | 
|  | set => SetXmlNodeString(_firstdatacolPath, value.ToString()); | 
|  | } | 
|  |  | 
|  | private ExcelPivotTableFieldCollection _fields; | 
|  |  | 
|  | /// <summary> | 
|  | /// The fields in the table | 
|  | /// </summary> | 
|  | public ExcelPivotTableFieldCollection Fields { | 
|  | get { | 
|  | if (_fields == null) { | 
|  | _fields = new(this, ""); | 
|  | } | 
|  | return _fields; | 
|  | } | 
|  | } | 
|  |  | 
|  | private ExcelPivotTableRowColumnFieldCollection _rowFields; | 
|  |  | 
|  | /// <summary> | 
|  | /// Row label fields | 
|  | /// </summary> | 
|  | public ExcelPivotTableRowColumnFieldCollection RowFields { | 
|  | get { | 
|  | if (_rowFields == null) { | 
|  | _rowFields = new(this, "rowFields"); | 
|  | } | 
|  | return _rowFields; | 
|  | } | 
|  | } | 
|  |  | 
|  | private ExcelPivotTableRowColumnFieldCollection _columnFields; | 
|  |  | 
|  | /// <summary> | 
|  | /// Column label fields | 
|  | /// </summary> | 
|  | public ExcelPivotTableRowColumnFieldCollection ColumnFields { | 
|  | get { | 
|  | if (_columnFields == null) { | 
|  | _columnFields = new(this, "colFields"); | 
|  | } | 
|  | return _columnFields; | 
|  | } | 
|  | } | 
|  |  | 
|  | private ExcelPivotTableDataFieldCollection _dataFields; | 
|  |  | 
|  | /// <summary> | 
|  | /// Value fields | 
|  | /// </summary> | 
|  | public ExcelPivotTableDataFieldCollection DataFields { | 
|  | get { | 
|  | if (_dataFields == null) { | 
|  | _dataFields = new(this); | 
|  | } | 
|  | return _dataFields; | 
|  | } | 
|  | } | 
|  |  | 
|  | private ExcelPivotTableRowColumnFieldCollection _pageFields; | 
|  |  | 
|  | /// <summary> | 
|  | /// Report filter fields | 
|  | /// </summary> | 
|  | public ExcelPivotTableRowColumnFieldCollection PageFields { | 
|  | get { | 
|  | if (_pageFields == null) { | 
|  | _pageFields = new(this, "pageFields"); | 
|  | } | 
|  | return _pageFields; | 
|  | } | 
|  | } | 
|  |  | 
|  | private const string _stylenamePath = "d:pivotTableStyleInfo/@name"; | 
|  |  | 
|  | /// <summary> | 
|  | /// Pivot style name. Used for custom styles | 
|  | /// </summary> | 
|  | public string StyleName { | 
|  | get => GetXmlNodeString(_stylenamePath); | 
|  | set { | 
|  | if (value.StartsWith("PivotStyle")) { | 
|  | try { | 
|  | _tableStyle = (TableStyles) | 
|  | Enum.Parse(typeof(TableStyles), value.Substring(10, value.Length - 10), true); | 
|  | } catch { | 
|  | _tableStyle = TableStyles.Custom; | 
|  | } | 
|  | } else if (value == "None") { | 
|  | _tableStyle = TableStyles.None; | 
|  | value = ""; | 
|  | } else { | 
|  | _tableStyle = TableStyles.Custom; | 
|  | } | 
|  | SetXmlNodeString(_stylenamePath, value, true); | 
|  | } | 
|  | } | 
|  |  | 
|  | private TableStyles _tableStyle = TableStyles.Medium6; | 
|  |  | 
|  | /// <summary> | 
|  | /// The table style. If this property is cusom the style from the StyleName propery is used. | 
|  | /// </summary> | 
|  | public TableStyles TableStyle { | 
|  | get => _tableStyle; | 
|  | set { | 
|  | _tableStyle = value; | 
|  | if (value != TableStyles.Custom) { | 
|  | SetXmlNodeString(_stylenamePath, "PivotStyle" + value); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | internal int CacheID { | 
|  | get => GetXmlNodeInt("@cacheId"); | 
|  | set => SetXmlNodeString("@cacheId", value.ToString()); | 
|  | } | 
|  | } |