添加自动筛选和排序会导致Excel崩溃

时间:2015-10-12 13:26:24

标签: c# excel openxml

我正在开发一个应用程序,您可以使用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" />

它已添加到sheetDatamergeCells之间的工作表中。

然后我可以在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>

不确定这可能是不是......

1 个答案:

答案 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应该在排序之前检查名称是否已定义,并在需要时自动创建它(如果您过滤而不是排序,它似乎会这样做。)