Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Excel计算仅在活动工作簿上,正在寻找解决方法_Excel_Vsto_Vba - Fatal编程技术网

Excel计算仅在活动工作簿上,正在寻找解决方法

Excel计算仅在活动工作簿上,正在寻找解决方法,excel,vsto,vba,Excel,Vsto,Vba,当打开多个Excel文件,并且VBA/VSTO代码调用计算函数,或打开自动计算时,Excel将痛苦地重新计算所有打开的工作簿,而不仅仅是活动工作簿 这是一个众所周知且广为报道的问题,已经存在多年,但微软似乎对解决它不感兴趣 可笑的是,在VBA和VSTO中,Microsoft都让我们能够: 重新计算特定工作表 重新计算所有打开的工作簿 …但没有选项仅重新计算一个特定工作簿 在我工作的金融公司,这是一个巨大的问题。我们的精算师拥有庞大的Excel文件,其中充满了公式,当他们在一个工作簿上单

当打开多个Excel文件,并且VBA/VSTO代码调用
计算
函数,或打开自动计算时,Excel将痛苦地重新计算所有打开的工作簿,而不仅仅是活动工作簿

这是一个众所周知且广为报道的问题,已经存在多年,但微软似乎对解决它不感兴趣

可笑的是,在VBA和VSTO中,Microsoft都让我们能够:

  • 重新计算特定工作表
  • 重新计算所有打开的工作簿
…但没有选项仅重新计算一个特定工作簿

在我工作的金融公司,这是一个巨大的问题。我们的精算师拥有庞大的Excel文件,其中充满了公式,当他们在一个工作簿上单击“计算”或我们在保存文件之前执行计算时,他们必须等待几分钟,以便所有其他打开的Excel文件也进行计算

有两种方法可以解决这个问题

您可以像这样运行一些VBA:

Application.Calculation = xlManual 
For Each sh In ActiveWorkbook.Worksheets 
    sh.Calculate 
Next sh 
但这并不能保证有效。“Sheet1”中可能包含指向“Sheet2”中单元格的公式,“Sheet2”中的其他单元格可能与“Sheet1”有依赖关系。因此,计算每个工作表一次可能不足以对工作簿执行完整的计算

或者,您可以在单独的实例中打开每个Excel文件(在打开Excel图标时按住ALT键)。但是,您将失去完整的Excel剪切粘贴功能,如下所述:

所以,我的问题是。。。是否有人找到解决此问题的方法

我只想重新计算活动的Excel工作簿中的单元格

我想知道是否可以添加一些VBA或VSTO,以便在开始对活动工作簿进行计算之前将所有非活动工作簿设置为“只读”,从而防止重新计算其他工作簿。但这是不可能的。“
工作簿.ReadOnly
”只能读取,不能以编程方式设置

或者向
工作表\u Calculate
事件添加一个处理程序,该事件检查正在运行的VBA代码是否属于活动工作簿,如果不属于活动工作簿,则中止尝试计算。。。?但是这个事件实际上是在计算完工作表之后开始的,所以太晚了

我们公司不可能是唯一一个受到这个问题困扰的公司


任何建议(升级到Lotus 1-2-3除外)?

此方法使用另一个Excel实例来避免多个工作簿计算。使用一个新实例的几行代码取自,它涉及一个类似的主题,您可能会感兴趣

您必须在特定情况下测试速度,因为关闭/打开时间可能不会超过避免的计算

宏步骤

  • 将计算设置为手动
  • 保存并退出所需的工作簿
  • 在Excel的新实例中打开它
  • 重新计算
  • 在Excel的原始实例中保存、关闭并重新打开
运行此脚本的关键点

  • 宏不能存在于要重新计算的工作簿中,因为在此过程中它会关闭(两次)。它应该放在其他一些“实用”工作簿中
代码-有关详细信息,请参阅注释

Sub CalculateWorkbook(WB As Workbook)
    ' Store path of given workbook for opening and closing
    Dim filepath As String
    filepath = WB.FullName
    ' Turn off calculation before saving
    Dim currentCalcBeforeSave As Boolean
    currentCalcBeforeSave = Application.CalculateBeforeSave
    Application.CalculateBeforeSave = False
    ' Store current calculation mode / screen update and then set it to manual
    Dim currentCalcMode As Integer, currentScreenUpdate As Integer
    currentCalcMode = Application.Calculation
    currentScreenUpdate = Application.ScreenUpdating
    Application.Calculation = xlCalculationManual
    Application.ScreenUpdating = False
    ' Close and save the given workbook
    WB.Close savechanges:=True
    ' Open a new INSTANCE of Excel - meaning seperate calculation calls
    Dim newExcel As Excel.Application
    Set newExcel = CreateObject("Excel.Application")
    ' Could make it visible so that any problems don't leave it hidden in the background
    ' newExcel.Visible = False
    ' Set the calculation mode to manual in the new instance sothat the workbook isn't calculated on opening.
    ' This can't be done without an existing workbook object.
    Dim tempWB As Workbook
    Set tempWB = newExcel.Workbooks.Add
    newExcel.Calculation = xlCalculationManual
    newExcel.CalculateBeforeSave = False
    ' Open the workbook in the new instance of Excel
    Dim newWB As Workbook
    Set newWB = newExcel.Workbooks.Open(filepath)
    ' Calculate workbook once
    newExcel.Calculate
    ' Close and save the workbook, tempworkbook and quit new instance
    newWB.Close savechanges:=True
    tempWB.Close savechanges:=False
    newExcel.Quit
    ' Re-open in the active instance of Excel
    Application.Workbooks.Open filepath
    ' Reset the application parameters
    Application.CalculateBeforeSave = currentCalcBeforeSave
    Application.ScreenUpdating = currentScreenUpdate
    Application.Calculation = currentCalcMode
End Sub
通过将希望重新计算的工作簿对象传递给上面的子对象来调用它(这可以通过按钮等来完成)


这已经在一个非常简单的示例工作簿上进行了测试,并且这个概念很有效。但是,请先在工作簿副本上进行测试,因为尚未对其进行完整的健壮性测试,并且没有错误处理。

我在FastExcel产品中使用的方法包括将所有非活动工作簿中的所有工作表的worker.EnableCalculation设置为false,将所有活动工作簿中的工作表设置为True

这是可行的,但其缺点是,当您更改活动工作簿时,下一次计算将成为新活动工作簿的完整计算:因此这是一种折衷

您可以从FastExcel V3 build 231.655.789.380的15天全功能试用版下载FastExcel的试用版,在您的情况下尝试一下

然后使用FastExcel计算选项并选中当前计算模式设置中的活动工作簿复选框


免责声明:我拥有、开发和销售FastExcel产品。包含活动工作簿计算代码的FastExcel组件是FastExcel V3 Calc

鉴于您可以在VBA中使用,我的第一个想法是您可以对依赖单元格进行某种树搜索,首先计算最后的分支,然后向后工作。。。使用
sh.Calculate
可以解决您提到的问题。你可以把它和电话配对。可能需要一些真正的思考来编写一个优雅的函数!谢谢Wolfie。。是的,我们确实考虑过这个。。但这将是一段噩梦般的代码,这就是为什么我认为在计算过程中以某种方式“禁用”所有其他打开的工作簿会更安全。问题是,当您重新启用对它们的计算时,无论如何都会启动计算,所以我们回到了开始的地方!!您可以使用VBA作为只读()打开工作簿@luklag以只读方式打开它们需要先关闭它们,这对OP来说不是很理想(我想)@MikeGledhill是的,当我写建议的时候,我意识到要使它变得健壮和快速(这就是重点!)可能会很棘手,我假设Excel的计算函数也有类似的功能,但经过了高度优化。我会想一想的,我也感觉到了这种痛苦。谢谢查尔斯。是的,我的团队和我之前讨论过这个“设置EnableCalculation”标志的想法,但我们决定反对它,就像我们的ActiveWorkbook一样