嗨,我使用以下方法来应用自动筛选器:
public static void ApplyAutofilter(string fileName, string sheetName, string reference)
{
using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true))
{
IEnumerable<Sheet> sheets = document.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>().Where(s => s.Name == sheetName);
var arrSheets = sheets as Sheet[] ?? sheets.ToArray();
string relationshipId = arrSheets.First().Id.Value;
var worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(relationshipId);
var autoFilter = new AutoFilter() { Reference = reference };
worksheetPart.Worksheet.Append(autoFilter);
worksheetPart.Worksheet.Save();
}
}
而且我有这个简单的Excel工作表:
<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9HYThqSC5qcGcifQ==” alt =“在此处输入图像描述”>
问题是当我将此方法称为:
ApplyAutofilter(@".\Test.xlsx", "Foo", "A0:A200");
或
ApplyAutofilter(@".\Test.xlsx", "Foo", "A1:A200");
未应用过滤器,并且在以下情况下尝试打开它时文件被损坏:
<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9PTnM5cS5qcGcifQ==” alt =“在此处输入图像描述”>
问题:知道如何将此自动文件管理器应用于Excel工作表而不损坏它吗?
这是由于您在XML中编写autoFilter
元素而导致的[[where。我打开了一个运行了您的代码的文件,并在Open XML Productivity Tool中将其打开。这表明错误是
从here看ECMA-376标准,Worksheet
的XML看起来像这样:
<xsd:complexType name="CT_Worksheet">
<xsd:sequence>
<xsd:element name="sheetPr" type="CT_SheetPr" minOccurs="0" maxOccurs="1"/>
<xsd:element name="dimension" type="CT_SheetDimension" minOccurs="0" maxOccurs="1"/>
<xsd:element name="sheetViews" type="CT_SheetViews" minOccurs="0" maxOccurs="1"/>
<xsd:element name="sheetFormatPr" type="CT_SheetFormatPr" minOccurs="0" maxOccurs="1"/>
<xsd:element name="cols" type="CT_Cols" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="sheetData" type="CT_SheetData" minOccurs="1" maxOccurs="1"/>
<xsd:element name="sheetCalcPr" type="CT_SheetCalcPr" minOccurs="0" maxOccurs="1"/>
<xsd:element name="sheetProtection" type="CT_SheetProtection" minOccurs="0" maxOccurs="1"/>
<xsd:element name="protectedRanges" type="CT_ProtectedRanges" minOccurs="0" maxOccurs="1"/>
<xsd:element name="scenarios" type="CT_Scenarios" minOccurs="0" maxOccurs="1"/>
<xsd:element name="autoFilter" type="CT_AutoFilter" minOccurs="0" maxOccurs="1"/>
<xsd:element name="sortState" type="CT_SortState" minOccurs="0" maxOccurs="1"/>
<xsd:element name="dataConsolidate" type="CT_DataConsolidate" minOccurs="0" maxOccurs="1"/>
<xsd:element name="customSheetViews" type="CT_CustomSheetViews" minOccurs="0" maxOccurs="1"/>
<xsd:element name="mergeCells" type="CT_MergeCells" minOccurs="0" maxOccurs="1"/>
<xsd:element name="phoneticPr" type="CT_PhoneticPr" minOccurs="0" maxOccurs="1"/>
<xsd:element name="conditionalFormatting" type="CT_ConditionalFormatting" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="dataValidations" type="CT_DataValidations" minOccurs="0" maxOccurs="1"/>
<xsd:element name="hyperlinks" type="CT_Hyperlinks" minOccurs="0" maxOccurs="1"/>
<xsd:element name="printOptions" type="CT_PrintOptions" minOccurs="0" maxOccurs="1"/>
<xsd:element name="pageMargins" type="CT_PageMargins" minOccurs="0" maxOccurs="1"/>
<xsd:element name="pageSetup" type="CT_PageSetup" minOccurs="0" maxOccurs="1"/>
<xsd:element name="headerFooter" type="CT_HeaderFooter" minOccurs="0" maxOccurs="1"/>
<xsd:element name="rowBreaks" type="CT_PageBreak" minOccurs="0" maxOccurs="1"/>
<xsd:element name="colBreaks" type="CT_PageBreak" minOccurs="0" maxOccurs="1"/>
<xsd:element name="customProperties" type="CT_CustomProperties" minOccurs="0" maxOccurs="1"/>
<xsd:element name="cellWatches" type="CT_CellWatches" minOccurs="0" maxOccurs="1"/>
<xsd:element name="ignoredErrors" type="CT_IgnoredErrors" minOccurs="0" maxOccurs="1"/>
<xsd:element name="smartTags" type="CT_SmartTags" minOccurs="0" maxOccurs="1"/>
<xsd:element name="drawing" type="CT_Drawing" minOccurs="0" maxOccurs="1"/>
<xsd:element name="drawingHF" type="CT_DrawingHF" minOccurs="0" maxOccurs="1"/>
<xsd:element name="picture" type="CT_SheetBackgroundPicture" minOccurs="0" maxOccurs="1"/>
<xsd:element name="oleObjects" type="CT_OleObjects" minOccurs="0" maxOccurs="1"/>
<xsd:element name="controls" type="CT_Controls" minOccurs="0" maxOccurs="1"/>
<xsd:element name="webPublishItems" type="CT_WebPublishItems" minOccurs="0" maxOccurs="1"/>
<xsd:element name="tableParts" type="CT_TableParts" minOccurs="0" maxOccurs="1"/>
<xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
注意,它是sequence
,因此项目的顺序很重要。在我的示例文件中,在autoFilter
元素之后添加了pageMargins
元素,这与上述架构相反。更改代码以将
autoFilter
元素写入正确的位置会修复您的代码。我不确定这是否是最有效的方法,但这应该可行。本质上,它向后推动workbook
的子元素,直到找到autoFilter
之后的第一个元素。一旦发现它使用InsertAfter
方法将autoFilter
插入正确的位置:
public static void ApplyAutofilter(string fileName, string sheetName, string reference) { using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, true)) { IEnumerable<Sheet> sheets = document.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>().Where(s => s.Name == sheetName); var arrSheets = sheets as Sheet[] ?? sheets.ToArray(); string relationshipId = arrSheets.First().Id.Value; var worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(relationshipId); var autoFilter = new AutoFilter() { Reference = reference }; OpenXmlElement preceedingElement = GetPreceedingElement(worksheetPart); worksheetPart.Worksheet.InsertAfter(autoFilter, preceedingElement); worksheetPart.Worksheet.Save(); } } public static OpenXmlElement GetPreceedingElement(WorksheetPart worksheetPart) { List<Type> elements = new List<Type>() { typeof(Scenarios), typeof(ProtectedRanges), typeof(SheetProtection), typeof(SheetCalculationProperties), typeof(SheetData) }; OpenXmlElement preceedingElement = null; foreach (var item in worksheetPart.Worksheet.ChildElements.Reverse()) { if (elements.Contains(item.GetType())) { preceedingElement = item; break; } } return preceedingElement; }
OpenXmlElement preceedingElement = GetPreceedingElement(worksheetPart);
worksheetPart.Worksheet.InsertAfter(autoFilter, preceedingElement);