使用Excel Interop的公式

时间:2012-09-18 19:36:38

标签: .net f# excel-interop

我正在使用F#和Excel Interop将数据输出到Excel电子表格。我的第一个方法是单独设置每个单元格:

worksheet.Range(range1).Value2 <- "=sum(a1:a10)"
worksheet.Range(range2).Value2 <- "=min(a1:a10)"
worksheet.Range(range3).Value2 <- "=max(a1:a10)"
(* etc *)

但是,当有大量公式时,这太慢了,所以我切换到了一个数组:

worksheet.Range(range).Value2 <- [| "=sum(a1:a10)"
                                    "=min(a1:a10)"
                                    "=max(a1:a10)" |]

worksheet.Range(range).Formula <- [| "=sum(a1:a10)"
                                     "=min(a1:a10)"
                                     "=max(a1:a10)" |]

但是,现在Excel只在单元格中显示这些字符串,而不是计算公式的值。我也尝试过:

worksheet.Range(range).FormulaArray <- [| "=sum(a1:a10)"
                                          "=min(a1:a10)"
                                          "=max(a1:a10)" |]

但这与每个公式的目标范围相混淆。我不确定那里发生了什么。 (Excel不会将其保留为"a1:a10",而是根据公式的位置转换目标范围。)

有更好的方法吗?

更新:我也尝试使用“= MIN($ G $ 2:$ G $ 5)”,但这产生了相同的效果,其中Excel只显示字符串而不评估公式。

对于它的价值,如果我进入单元格,擦除然后重新添加公式中的任何字符,当我点击“输入”时,Excel将对其进行评估。

更新2 :我还尝试了以下内容:

worksheet.Range(range).FormulaR1C1 <- [| "=sum(R2C[0]:R4C[0])"
                                          "=average(R2C[0]:R4C[0])"
                                          "=min(R2C[0]:R4C[0])"
                                          "=max(R2C[0]:R4C[0])" |]

但是我遇到了同样的问题:Excel将它们渲染为字符串而不是评估公式。

3 个答案:

答案 0 :(得分:7)

Daniel的答案应该有效,但我发现使用R1C1格式的公式更容易。您的代码应如下所示:

ws.Range(range).FormulaR1C1 <- [| "=sum(R1C1:R10C1)";
                                  "=min(R1C1:R10C1)"; 
                                  "=max(R1C1:R10C1)" |]

这将生成具有绝对地址的公式。您可以使用R [vertical_offset] C [horizo​​ntal_offset]构建相对地址。选择整行或列也很容易:R1是整行第一行,C4是整个“D”列。

使用纯F#中的String.Format或sprintf轻松构建R1C1地址。

编辑:我快速检查了一下vba,它无法正常工作。 Excel将第一个数组元素放在范围内的每个单元格中。无论如何,R1C1寻址点仍然有效。它就像标题公式的魅力(即ws.Range(headerRange).FormulaR1C1&lt; - “= sum(R2C [0]:R10C [0]”),所以我会保留答案。

EDIT2:我认为ArrayFormula适用于array formulas,所以它也无效。

EDIT3:我做了一些研究,找到了一些我认为不可能的答案:)。

首先,将这些字符串作为公式,将它们转换为对象:

let formulas : obj[] = [| "=sum(R1C1:R10C1)";
                          "=min(R1C1:R10C1)"; 
                          "=max(R1C1:R10C1)" |]

然后将其放入FormulaR1C1:

ws.Range(range).FormulaR1C1 <- formulas

第二,重要部分:上面的例子假设范围是三个细胞的水平范围(即F3:H3)。如果你试图把它放在垂直范围内(即F3:F5),你会注意到,这个和公式在范围内的每个单元格中重复。我敢打赌,在这种情况下,公式应该是二维对象数组,第一行外部数组是公式数组,但我在尝试将其放入range.FormulaR1C1时得到SafeArrayTypeObjectExtension。看看this msdn docs

  

如果范围是一维或二维范围,则可以将公式设置为具有相同尺寸的Visual Basic数组。同样,您可以将公式放入Visual Basic数组中。

稍后我会再看一下这个例外。

答案 1 :(得分:1)

假设您的第一种方法有效且意味着类型(而不是执行)太慢,它可能更快/更容易像这样更新一堆单元格

[
  range1, "=sum(a1:a10)"
  range2, "=min(a1:a10)"
  range3, "=max(a1:a10)"
  ...
]
|> List.iter (fun (range, value) -> worksheet.Range(range).Value2 <- value)

答案 2 :(得分:1)

或者你可以从fsnip.net http://fssnip.net/aV上的这个片段中获得一些想法,它实现了Excel的一些高阶函数。 (与使用电子表格设备相比,这是一个更长的镜头性能,因为该片段并不是真正的性能。)