添加自动过滤器和排序会导致 Excel 崩溃
Adding autofilter and sorting causes Excel to crash
我正在开发一个应用程序,您可以在其中使用 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
,然后删除该过滤器,您现在可以排序而不会崩溃。我在应用过滤器并删除它后保存了一个文件,现在该文件很好,但是查看 "repaired" 文件的 XML,我没有看到任何明显的区别。
有谁知道可能导致问题的原因是什么?除了将其添加到工作表之外,在应用自动筛选器时我还应该做些什么吗?
注意:我们使用的是 Excel 2010(版本 14.0.7153.5000)
这是一个示例 file(单击下载,它将作为 .zip
下载。重命名为 .xlsx
以在 Excel 中打开。启用编辑,select 其中一列并尝试排序)。
编辑:再尝试一下。如果您在 Excel 中重新保存文件,它仍然损坏。但是,如果您首先应用过滤器(然后清除它)然后重新保存到 Excel,您将得到一个工作文件。仔细观察这两个文件(仍然损坏的重新保存文件和现在工作的文件),我确实注意到在应用(并清除)过滤器后工作簿中添加了这个额外的位:
<x:definedNames>
<x:definedName name="_xlnm._FilterDatabase" localSheetId="0" hidden="1">'Sheet 1'!$A:$E</x:definedName>
</x:definedNames>
不确定这是否是某种东西...
好的,看来这里的神奇公式是按照我在编辑中的建议添加 DefinedNames
部分:
<x:definedName name="_xlnm._FilterDatabase" localSheetId="0" hidden="1">'Sheet 1'!$A:$E</x:definedName>
显然 _xlmn._FilterDatabase
是自动过滤器工作所必需的(至少排序是这样)。我想如果你过滤时它不存在,它就会被创建,但如果你排序时它不存在,它就会爆炸 Excel.
因此您需要sheet名称和单元格引用来填写它。
查看 Open XML 标准,在 definedName
的第 18.2.5 节中,我看到了:
Filter & Advanced Filter
_xlnm .Criteria: this defined name refers to a range containing the criteria values
to be used in applying an advanced filter to a range of data.
_xlnm ._FilterDatabase: can be one of the following
a. this defined name refers to a range to which an advanced filter has been
applied. This represents the source data range, unfiltered.
b. This defined name refers to a range to which an AutoFilter has been
applied.
因此,您似乎需要为每个具有过滤器的 sheet 添加一个 _xlnm._FilterDatabase
(似乎无法在单个 [=36= 上设置多个过滤器) ]).无论您使用过滤器有多少个 sheet,名称都是相同的 _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:",
sheet.Name,
leftColumnLetter,
topRowIndex,
rightColumnLetter,
bottomRowIndex))
{
Name = "_xlnm._FilterDatabase",
LocalSheetId = sheet.SheetId - 1,
Hidden = true
});
这似乎是在解决 Excel 中的错误。 Excel 应该在排序之前检查名称是否已定义,并在需要时自动创建它(如果您过滤而不是排序,它似乎会这样做)。
我正在开发一个应用程序,您可以在其中使用 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
,然后删除该过滤器,您现在可以排序而不会崩溃。我在应用过滤器并删除它后保存了一个文件,现在该文件很好,但是查看 "repaired" 文件的 XML,我没有看到任何明显的区别。
有谁知道可能导致问题的原因是什么?除了将其添加到工作表之外,在应用自动筛选器时我还应该做些什么吗?
注意:我们使用的是 Excel 2010(版本 14.0.7153.5000)
这是一个示例 file(单击下载,它将作为 .zip
下载。重命名为 .xlsx
以在 Excel 中打开。启用编辑,select 其中一列并尝试排序)。
编辑:再尝试一下。如果您在 Excel 中重新保存文件,它仍然损坏。但是,如果您首先应用过滤器(然后清除它)然后重新保存到 Excel,您将得到一个工作文件。仔细观察这两个文件(仍然损坏的重新保存文件和现在工作的文件),我确实注意到在应用(并清除)过滤器后工作簿中添加了这个额外的位:
<x:definedNames>
<x:definedName name="_xlnm._FilterDatabase" localSheetId="0" hidden="1">'Sheet 1'!$A:$E</x:definedName>
</x:definedNames>
不确定这是否是某种东西...
好的,看来这里的神奇公式是按照我在编辑中的建议添加 DefinedNames
部分:
<x:definedName name="_xlnm._FilterDatabase" localSheetId="0" hidden="1">'Sheet 1'!$A:$E</x:definedName>
显然 _xlmn._FilterDatabase
是自动过滤器工作所必需的(至少排序是这样)。我想如果你过滤时它不存在,它就会被创建,但如果你排序时它不存在,它就会爆炸 Excel.
因此您需要sheet名称和单元格引用来填写它。
查看 Open XML 标准,在 definedName
的第 18.2.5 节中,我看到了:
Filter & Advanced Filter
_xlnm .Criteria: this defined name refers to a range containing the criteria values to be used in applying an advanced filter to a range of data.
_xlnm ._FilterDatabase: can be one of the following
a. this defined name refers to a range to which an advanced filter has been applied. This represents the source data range, unfiltered.
b. This defined name refers to a range to which an AutoFilter has been applied.
因此,您似乎需要为每个具有过滤器的 sheet 添加一个 _xlnm._FilterDatabase
(似乎无法在单个 [=36= 上设置多个过滤器) ]).无论您使用过滤器有多少个 sheet,名称都是相同的 _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:",
sheet.Name,
leftColumnLetter,
topRowIndex,
rightColumnLetter,
bottomRowIndex))
{
Name = "_xlnm._FilterDatabase",
LocalSheetId = sheet.SheetId - 1,
Hidden = true
});
这似乎是在解决 Excel 中的错误。 Excel 应该在排序之前检查名称是否已定义,并在需要时自动创建它(如果您过滤而不是排序,它似乎会这样做)。