如何停止Excel提示重新打开工作簿?

7
我有一个只读的Excel工作簿,其中包含一个VBA应用程序。该应用程序将需要保存的任何数据保存在数据库中,并且工作簿始终不保存就关闭(通过在BeforeClose中设置ThisWorkbook.Saved = True)。
我有以下问题:
用户在Windows资源管理器中双击工作簿,工作簿打开。
用户第二次在Windows资源管理器中双击工作簿。
Excel提示:“MyWorkbook.xls已经打开。重新打开会导致您所做的任何更改被丢弃。您要重新打开MyWorkbook.xls吗?”
如果用户单击“Yes”,则重新打开工作簿而不执行已经打开的实例的BeforeClose事件处理程序
这是我的应用程序中的问题,因为这意味着BeforeClose事件处理程序中的一些重要清除代码未被执行。
有人能提出一个VBA解决方案吗?可以是:
抑制重新打开工作簿的提示。而是静默使用已经打开的实例。
以某种方式在原始实例关闭之前获取BeforeClose或其他事件处理程序,以便我可以运行我的清理代码。
更新:
这是Excel 2003。
我可以通过在Workbook_SheetChanged事件处理程序中设置“ThisWorkbook.Saved = True”来消除不需要的提示(VBA应用程序负责保存需要保存在数据库中的任何数据,因此我不关心Excel保存更改)。
然而,这并不能解决我的问题:如果我这样做,那么在资源管理器中双击工作簿会默默地重新打开工作簿,但仍然不调用我的“BeforeClose”事件处理程序。
因此,重新表述问题:
有没有一种方法使用VBA来检测和拦截以这种方式重新打开工作簿?
更新2
接受BKimmel的答案-似乎没有从工作簿内部拦截此事件的VBA方法。
我要实现的解决方案是将应用程序代码移动到XLA插件中,该插件在加载工作簿时自动加载(如果尚未加载)。插件可以处理Open和BeforeClose事件,并存储它需要进行清理的信息。

@Joe,也许你可以告诉大家你使用的Excel确切版本?这可能会影响人们能够给出的答案。:-) - Onorio Catenacci
3个回答

2
您也可以通过以下方式禁止提示: 这将重新打开一个已打开的文件,而不会出现警告。 但请注意,任何更改都将被丢弃!
Application.DisplayAlerts = False
Workbooks.Open (sPath)
Application.DisplayAlerts = True

来自Excel论坛

这个解决方案符合我的需求


2

您可以使用一些特殊的应用程序事件来处理重新打开工作簿时并手动触发Workbook_Close代码:

创建一个名为ApplicationController的类模块,并使用以下代码:

Public WithEvents CApp As Application
Public CurrentWB as Workbook

Private Sub CApp_WorkbookOpen(ByVal wb As Excel.Workbook)


Dim sPathName As String
sPathName = wb.Name
if sPathName = CurrentWB.Name then CallSomeMethod()

End Sub

那么在你的“workbook_load”事件中,可以这样做:

Public controller as new ApplicationController
Private Sub Workbook_Open()
set controller.CApp = Excel.Application
set controller.CurrentWB = ThisWorkbook
End Sub

现在当Excel打开新工作簿时,您将捕获该事件并运行您的安全方法。如果需要,您甚至可以防止重新打开工作簿。

不行。我尝试过处理Application_WorkbookOpen事件,但它是在上一个实例已经关闭之后才被调用的。 - Joe
你能否在工作簿打开时运行这段代码,而不是在关闭时运行?作为“一天开始”的过程或其他什么吗?或者在工作簿关闭时设置一个标志,除非存在该标志,否则代码将在打开时运行? - Matthew Rathbone
不,我不能在Workbook_Open中运行它。而且我也不能在关闭时设置标志,因为工作簿是只读的。无论如何还是谢谢。 - Joe

2

人们可能认为这个问题很简单,但实际上它很棘手。在我使用Excel VBA工作的7年中,我尝试过每一个事件和应用程序/工作簿属性,但都无法想出任何优雅的解决方案...我认为简短的答案是这个问题没有真正的简洁解决方案(如果有,我真的很想看到)。这是坏消息。

好消息是我认为有方法可以解决这个问题...其中一种方式更加优雅,但需要你重新思考一些方法,另一种方式比较麻烦,但可能更简单。

更加优雅的方式涉及重新思考和重构你的方法...我认为我在工作中从未遇到过这个问题的原因是,在每个方法结束时,工作簿都处于“良好”状态...或者换句话说,如果需要“清理”,则在每个方法的末尾完成。如果这样做会带来巨大的性能开销,你可以考虑设置布尔标志并限制是否在其他方法的末尾运行它。(即runCleanup = ReturnTrueIfCleanupIsNeeded() 如果(runCleanup = true)则 CleanupMethod() End If)

更加麻烦的方式涉及将整个工作簿本身变成一种“临时互斥锁”,方法如下:
1)在WorkBookOpen事件中将整个(原始的)工作簿复制到另一个(临时的)工作簿,并使用temp上的“SaveAs”方法将其放置在一个单独的位置。
2)存储(原始的)路径。
3)添加代码到WorkBook打开事件,检查(temp)是否存在,如果存在,则A)立即关闭自身并激活temp或B)用(temp)覆盖自身,然后使用SaveAs
4)在用户保存工作簿之前捕获事件,并将其保存到original位置和temp位置。
5)在WorkBookClose事件中,运行任何需要的清理并将temp保存回其原始位置。

所有这些的目的是为了避免打开工作簿两次时发生的“冲突”-实际上,通过在第一次打开它时创建一个temp工作簿并将其保存在不同的位置(也许你甚至可以隐藏文件?),你确保当用户点击原始文件时,它不会与他们已经在应用程序中处理的数据发生冲突。(当然,这也有自己的问题/问题,比如“如果我不知道用户可以访问哪些路径来保存临时文件”或“如果用户打开了temp XLS文件...但这就是为什么我称之为dirt方式)

我知道这很多,特别是如果你不习惯使用VBA;如果你想让我发布一些代码来帮助你完成其中的任何步骤,请留言,我会尽力而为。

感谢您提出这个有趣的问题。

无论如何还是谢谢。将内容复制到临时工作簿是一个有趣的想法,但我认为重新设计应用程序以消除在关闭时清理的依赖关系会更容易。在这种情况下,BeforeClose事件没有被触发,这对我来说似乎是一个错误。 - Joe
注意:我从未保存过工作簿(它是只读的),因此关于在临时文件和原始文件中保存的内容在我的情况下不必要。 - Joe
是的,我会说至少MSDN文档应该说明由于这个原因你不能依赖BeforeClose事件。我仍然很感兴趣看看是否有其他人能想出我们没有考虑到的创意解决方案。 - BKimmel
再次感谢。如问题编辑中所述,我将把应用程序移入XLA插件中(这可能是更好的解决方案)。 - Joe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接