我正在开发一个应用程序,您可以使用OpenXML将一些数据导出到Excel文件中。除了使用自动过滤器,一切正常。我们的想法是在数据主体中添加一个自动过滤器,以便用户自动拥有对数据进行过滤和排序的控件。所以在代码中,我做了类似的事情:
var filter = new AutoFilter() { Reference = string.Format("{0}:{1}", topLeftCellReference, bottomRightCellReference ) };
worksheet.AppendChild(filter);
在导出的XLSX中,它显示如下:
<x:autoFilter ref="A4:L33" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main" />
它已添加到sheetData
和mergeCells
之间的工作表中。
然后我可以在Excel中打开此过滤器,它可以正常工作。预计如果您尝试对列进行排序,列将排序,然后Excel崩溃。保存和重新加载文件(强制Excel清理所有内容)并不能解决问题。但是,如果您首先应用过滤器(比如过滤一列到> 10
,然后删除该过滤器,您现在可以排序而不会崩溃。我在应用过滤器并删除它后保存了一个文件,现在该文件很好,但是看一下&#34;修复过的&#34;文件的XML,我没有看到任何明显的区别。
有人知道可能导致问题的原因吗?除了将自动过滤器添加到工作表之外,还有什么我应该做的吗?
注意:我们使用的是Excel 2010(版本14.0.7153.5000)
以下是file的示例(点击下载,然后以.zip
的形式下载。重命名为.xlsx
以在Excel中打开。启用编辑,选择一个列并尝试排序)。
编辑:再玩这个。如果您在Excel中重新保存文件,它仍然会被破坏。但是,如果您首先应用过滤器(然后清除它)然后在Excel中重新保存,则会获得一个工作文件。仔细观察两个文件(仍然破坏的重新存档文件和现在正在运行的文件),我注意到在应用过滤器(并清除)后,这个额外的位被添加到工作簿中:
<x:definedNames>
<x:definedName name="_xlnm._FilterDatabase" localSheetId="0" hidden="1">'Sheet 1'!$A$1:$E$11</x:definedName>
</x:definedNames>
不确定这可能是不是......
答案 0 :(得分:4)
好的,所以这里似乎神奇的公式是按照我在编辑中的建议添加DefinedNames
部分:
<x:definedName name="_xlnm._FilterDatabase" localSheetId="0" hidden="1">'Sheet 1'!$A$1:$E$11</x:definedName>
显然,自动过滤器需要_xlmn._FilterDatabase
才能工作(至少是排序)。我想如果你在过滤时它不存在,它就会被创建,但是如果排序时它不存在,那就会炸毁Excel。
所以你需要使用sheetname和cell引用来填充它。
通过开放XML标准,在definedName
的第18.2.5节中,我看到了这一点:
过滤器&amp;高级过滤器
_xlnm .Criteria:此定义的名称是指包含标准值的范围 用于将高级过滤器应用于一系列数据。
_xlnm ._FilterDatabase:可以是以下之一
一个。此定义的名称是指高级过滤器所在的范围 应用。这表示未经过滤的源数据范围。
湾此定义的名称是指AutoFilter的范围 应用
因此,您似乎需要为每个包含过滤器的工作表添加_xlnm._FilterDatabase
(看起来单个工作表上无法使用多个过滤器)。无论您使用过滤器有多少张,因此名称与_xlmn_FilterDatabase
相同,因为我认为只有名称和localSheetId
的组合必须是唯一的。
所以最后,我有这样的事情:
var filter = new AutoFilter() { Reference = string.Format("{0}:{1}", topLeftCellReference, bottomRightCellReference ) };
worksheet.AppendChild(filter);
workbookPart.Wookbook.DefinedNames.AppendChild(new DefinedName(string.Format("'{0}'!$A${1}:${2}${3}",
sheet.Name,
leftColumnLetter,
topRowIndex,
rightColumnLetter,
bottomRowIndex))
{
Name = "_xlnm._FilterDatabase",
LocalSheetId = sheet.SheetId - 1,
Hidden = true
});
这似乎正在解决Excel中的错误。 Excel应该在排序之前检查名称是否已定义,并在需要时自动创建它(如果您过滤而不是排序,它似乎会这样做。)