我正在开发一个应用程序,您可以使用OpenXML将一些数据导出到Excel文件.除了使用自动过滤器,一切正常.我们的想法是在数据主体中添加一个自动过滤器,以便用户自动拥有对数据进行过滤和排序的控件.所以在代码中,我做这样的事情:
var filter = new AutoFilter() { Reference = string.Format("{0}:{1}", topLeftCellReference, bottomRightCellReference ) };
worksheet.AppendChild(filter);
Run Code Online (Sandbox Code Playgroud)
在导出的XLSX中,它看起来像这样:
<x:autoFilter ref="A4:L33" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main" />
Run Code Online (Sandbox Code Playgroud)
而且它加入之间的工作sheetData和mergeCells.
然后,我可以在Excel中打开此过滤器,它工作正常.预计如果您尝试对列进行排序,列将排序,然后Excel崩溃.保存和重新加载文件(强制Excel清除所有内容)不能解决问题.但是,如果您首先应用过滤器(比如过滤一个列> 10,然后删除该过滤器,您现在可以排序而不会崩溃.我在应用过滤器并删除它后保存了一个文件,现在该文件很好,但是查看XML对于"已修复"的文件,我没有看到任何明显的区别.
有谁知道可能导致问题的原因是什么?除了将其添加到工作表之外,在应用自动过滤器时还有什么我应该做的吗?
注意:我们使用的是Excel 2010(版本14.0.7153.5000)
这是一个示例文件(单击下载,它将下载为.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>
Run Code Online (Sandbox Code Playgroud)
不确定这可能是不是......
好的,所以这里的神奇公式似乎是添加DefinedNames我在编辑中建议的部分:
<x:definedName name="_xlnm._FilterDatabase" localSheetId="0" hidden="1">'Sheet 1'!$A$1:$E$11</x:definedName>
Run Code Online (Sandbox Code Playgroud)
显然,_xlmn._FilterDatabase自动过滤器需要工作(至少用于排序)。我想如果你过滤时它不在那里,它就会被创建,但如果你排序时它不在那里,它就会炸毁 Excel。
所以你需要工作表名和单元格引用来填充它。
查看 Open XML 标准,在 的第 18.2.5 节中definedName,我看到了这一点:
过滤器和高级过滤器
_xlnm .Criteria:这个定义的名称指的是一个范围,其中包含在将高级过滤器应用于一系列数据时要使用的标准值。
_xlnm ._FilterDatabase:可以是以下之一
一种。这个定义的名称是指应用了高级过滤器的范围。这表示未过滤的源数据范围。
湾 此定义的名称是指已应用自动筛选的范围。
因此,您似乎需要_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
});
Run Code Online (Sandbox Code Playgroud)
这似乎确实解决了 Excel 中的错误。Excel 应该在排序之前检查名称是否已定义,并在需要时自动创建它(如果您是过滤而不是排序,它似乎会这样做)。
| 归档时间: |
|
| 查看次数: |
2139 次 |
| 最近记录: |