【问题标题】:How can I programmatically create an Excel "sort/Filter combobox"?如何以编程方式创建 Excel“排序/筛选组合框”?
【发布时间】:2015-11-04 19:02:25
【问题描述】:

我正在对手动创建的电子表格进行逆向工程以进行动态创建。大多数单元格都填充了简单的数据,但有几个是“排序/过滤”下拉菜单,如下所示:

如何动态创建这样的控件?

有没有办法在 Excel 电子表格中“查看源代码”以查看生成这些控件可能需要什么样的代码?

更新

改编MacroMark的代码,编译:

var rangeMonthYears = _xlSheet.Range[_xlSheet.Cells[7, 3], _xlSheet.Cells[7, 15]];
        object sortFilterCombobox = (object)rangeMonthYears.AutoFilter(1, System.Reflection.Missing.Value, XlAutoFilterOperator.xlAnd, System.Reflection.Missing.Value, true);
        _xlSheet.Cells["6", "C"] = sortFilterCombobox; //MonthLabel; 

...但它崩溃了,向我展示了这个责备说明:

我是怎么误入歧途的?

更新 2

为了在下面的评论中回答 MacroMarc,这里是遗留/模型电子表格中过滤器控件的屏幕截图(我正在对其进行逆向工程):

在这种情况下,我从列表中取消选择“11 月”,以便将其删除,如您所见。所以用户选择的内容会影响下面列的可见性。

更新 3

由于所有这些花哨的内容都融入了旧版电子表格,我现在正在考虑将其保存为模板,并根据需要简单地替换单元格内容。有什么理由不可行吗?

如果不是,要完成此操作,我是否应该将现有的电子表格保存为“启用 Excel 宏的工作簿”?

更新 4

我尝试像这样调整 MacroMarc 的答案:

Range monthYearCells = _xlSheet.Range[_xlSheet.Cells[COLUMN_HEADING_ROW, MONTH1_COL], _xlSheet.Cells[COLUMN_HEADING_ROW, MONTH13_COL]];
object monthFilter = (object)monthYearCells.AutoFilter(1, System.Reflection.Missing.Value, XlAutoFilterOperator.xlAnd, System.Reflection.Missing.Value, true);
var monthFilterCell = (Range)_xlSheet.Cells[6, 3];
monthFilterCell.Value = monthFilter;

...但是遇到了运行时异常:

是导致问题的最后一行(将 monthFilter 分配给范围的 Value 属性)吗?如果是这样,我应该将monthFilter分配给什么,或者我应该如何处理它?

【问题讨论】:

  • 啊,我明白了。我给你的代码只是为了在 Excel 范围内启用“过滤下拉菜单”。它们自动出现在该范围的第一行。您似乎想从 Excel 单元格中连续捕获一年中的十二个月,并将它们显示在完全不同的单元格中的下拉列表中。即您希望转移“过滤器下拉菜单”。不会使用该语法/对象。这可能会导致一个又一个问题。也许最好解释一下您希望达到的目标,我们会尽力为您提供最佳建议。 “过滤器下拉菜单”是一种在列顶部下拉的功能。
  • 如果您注释掉 "_xlSheet.Cells["6", "C"] = sortFilterCombobox; //MonthLabel;"线??您是否看到每个月的过滤器下拉列表?只是检查那部分...... Excel中有各种各样的过滤器,包括更棘手的数据透视表过滤器。不太确定您的 C# 应用程序的目的是什么...
  • “更多命令”选项位于我发布的第一个屏幕截图所示的菜单中,而不是第二个。要在第二个窗口中查看开发人员选项卡选项,请从第二个屏幕截图(带有“选择命令”标签的组合框)顶部的下拉列表中选择“开发人员选项卡”。
  • 另外,我找到了您的问题的原因,并相应地更新了我的答案。
  • 好的。看起来您可能在数据透视表中。你能证实这一点吗?如果您单击 sep 14,您应该会在功能区上看到一个新的彩色标签弹出,上面写着数据透视表工具。

标签: c# excel office-interop excel-interop


【解决方案1】:

过滤器是由 Excel 表格中的范围本地创建的,或者可能由 Excel 界面上的过滤器按钮创建。正如 Joshua 所说,您可以尝试在 VBA 中编写脚本,但从您的问题标签看来,您正在使用 C# 和 Excel-Interop(??)

尝试在您的 C# 代码中使用范围对象句柄并应用 .Autofilter 方法。

object result = (object)oRange.AutoFilter(1, System.Reflection.Missing.Value,ExApp.XlAutoFilterOperator.xlAnd,System.Reflection.Missing.Value, true);

ExApp 上面是我的 Interop.Excel 命名空间的别名。

至于开发人员选项卡,请查看 Google 上的自定义功能区选项以获取您的 Excel 版本。右键单击功能区,或者文件-->选项--等

更新

好的,要修改数据透视字段的排序和过滤属性,您需要获取数据透视字段的句柄,例如,如果您的“月份”过滤器位于单元格 D5 中,您可以执行以下操作:

Range oRange = oSheet.get_Range("D5", "D5");
PivotField pf = oRange.PivotField;
pf.AutoSort((int)XlSortOrder.xlDescending, "Month");   //this sorts in reverse order            
pf.PivotItems(2).Visible = false;   //this makes the second item deselected in filter

【讨论】:

  • 谢谢;请参阅更新 2。
【解决方案2】:

不,您不能在 Excel 电子表格上“查看源代码”。但是,您可以打开 VBA 编辑器并查看其中写入了哪些代码。在现代版本的 Excel 中,如何做到这一点可能并不那么明显。在 Excel 窗口顶部,查找小箭头,单击它,将出现一个下拉菜单。

在列表的底部,您会看到一个名为“更多命令”的选项。单击此处,将打开以下窗口。

然后您可以过滤命令列表。选择“开发人员选项卡”,在右侧您将看到一个名为“Visual Basic”的命令。您还有其他用于录制宏的命令,因此请添加整个列表。从我的第一个屏幕截图中可以看出,我已经在我的 Excel 副本中添加了这些内容。

请注意,您可能还需要调整安全设置。

既然您知道如何打开 VBA 编辑器,并且您拥有宏命令,您可以查看创建过滤器的代码,或者您可以自己创建过滤器并录制宏以查看它是如何完成的。生成的宏将在 VBA 中,您可以随意修改它。

首先单击“录制宏”的快速访问工具栏图标,然后通过在要过滤的表格的第一行中选择一个单元格来添加过滤器,然后单击数据选项卡;点击过滤器。

录制宏后,您应该会在 VBA 编辑器中看到如下内容:

Sub Macro1()
'
' Macro1 Macro
'

'
    Selection.AutoFilter
    ActiveSheet.Range("$A$1:$D$6").AutoFilter Field:=3, Criteria1:="1023123"
    Selection.AutoFilter
End Sub

现在我们已经讨论了整个“开源”问题,下面是互操作问题的解决方案。我已经获取了您的代码,对其进行了更改,并对其进行了测试以重现错误并发现了问题所在。该过程必须仅选择表格的一部分或电子表格的完全空白区域。当 Excel 尝试查找要筛选的范围的角时,它会遇到问题,因为没有可识别的角要查找。以此为例:

    Excel.Application app = new Excel.Application();
    app.Visible = true;
    Excel.Workbook wk = app.Workbooks.Add();
    Excel.Worksheet sh = wk.Sheets[1];
    sh.Cells[1, 1] = "col1";
    sh.Cells[1, 2] = "col2";
    sh.Cells[1, 3] = "col3";
    sh.Cells[1, 4] = "col4";
    sh.Cells[2, 1] = "data";
    sh.Cells[2, 2] = "data";
    sh.Cells[2, 3] = "data";
    sh.Cells[2, 4] = "data";
    sh.Cells[3, 1] = "data2";
    sh.Cells[3, 2] = "data2";
    sh.Cells[3, 3] = "data2";
    sh.Cells[3, 4] = "data2";

    //Excel.Range r1 = sh.Range[sh.Cells[1, 1], sh.Cells[3, 4]]; //this works
    Excel.Range r2 = sh.Range[sh.Cells[7, 3], sh.Cells[7, 15]]; //this fails
    //object sortFilterCombobox1 = (object)r1.AutoFilter(1, System.Reflection.Missing.Value, Excel.XlAutoFilterOperator.xlAnd, System.Reflection.Missing.Value, true);
    object sortFilterCombobox2 = (object)r2.AutoFilter(1, System.Reflection.Missing.Value, Excel.XlAutoFilterOperator.xlAnd, System.Reflection.Missing.Value, true);

在下面的屏幕截图中,我突出显示了代码尝试放置过滤器的行,它是空的。因此,这里发生的情况是代码由于某种原因没有引用您正在使用的电子表格的正确区域。

解决此问题的一种方法是引用顶行中的第一个单元格,而不是整行。只要表格中没有空隙,Excel就会找到整个表格。

所以尝试在这个范围而不是整个范围上应用自动过滤:

_xlSheet.Cells[7, 3]

另外,如果您不知道,我应该指出,但是当您将“sortFilterCombobox”分配给一个单元格时,您实际上是在将一个布尔值弹出到单元格中。 AutoFilter 函数返回一个布尔值,而不是过滤器对象本身。

【讨论】:

  • 哦,它正在使用互操作。我会进行调查,然后更新我的答案。
  • 其实 73...715 对我来说是正确的范围;这就是存在月份标签的地方(9 月 14 日、10 月 14 日等)
  • 尝试对包含列标签而不是整行的行中的第一个单元格进行自动过滤。
猜你喜欢
  • 1970-01-01
  • 2011-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-10
  • 1970-01-01
  • 2010-11-27
相关资源
最近更新 更多