【问题标题】:How to stop Excel from prompting to reopen a workbook?如何阻止 Excel 提示重新打开工作簿?
【发布时间】:2010-09-16 06:18:39
【问题描述】:

我有一个包含 VBA 应用程序的只读 Excel 工作簿。应用程序将需要保存在数据库中的所有数据保存在数据库中,并且工作簿始终关闭而不保存(通过在 BeforeClose 中设置 ThisWorkbook.Saved = True)。

我有以下问题:

  • 用户在 Windows 资源管理器中双击工作簿,工作簿打开。

  • 用户在 Windows 资源管理器中再次双击工作簿。

  • Excel 提示:“MyWorkbook.xls 已打开。重新打开会导致放弃您所做的任何更改。是否要重新打开 MyWorkbook.xls?”

  • 如果用户单击“是”,则重新打开工作簿而不执行已打开实例的 BeforeClose 事件处理程序

这是我的应用程序中的一个问题,因为这意味着 BeforeClose 事件处理程序中的一些重要清理代码没有被执行。

任何人都可以为此建议一个 VBA 解决方案。可能是:

  • 抑制重新打开工作簿的提示。而是静默使用已经打开的实例。

  • 以某种方式让 BeforeClose 或其他一些事件处理程序在原始实例关闭之前运行,这样我就可以运行我的清理代码了。

更新:

这是 Excel 2003。

我可以通过在 Workbook_SheetChanged 事件处理程序中设置“ThisWorkbook.Saved = True”来摆脱不需要的提示(VBA 应用程序负责保存任何需要保存在数据库中的数据,所以我不在乎关于让 Excel 保存更改)。

但这并不能解决我的问题:如果我这样做,则在资源管理器中双击工作簿会静默地重新打开工作簿,但仍会这样做,而无需通过“BeforeClose”事件处理程序调用。

所以换个说法:

  • 是否有使用 VBA 来检测和拦截以这种方式重新打开的工作簿?

更新 2

接受 BKimmel 的回答 - 似乎没有 VBA 方法可以从工作簿中拦截此事件。

我将实施的解决方案是将应用程序代码移动到 XLA 加载项中,该加载项会在加载工作簿时自动加载(如果尚未加载)。加载项可以处理 Open 和 BeforeClose 事件,并存储进行清理所需的信息。

【问题讨论】:

  • @Joe,也许你可以告诉人们 Excel 的确切版本?这可能会改变人们可以给你的答案。 :-)

标签: excel vba


【解决方案1】:

伙计……这似乎很简单,但它是一个艰难的。我玩弄了我在使用 Excel VBA 的 7 年左右的经验中能想到的每一个事件和应用程序/工作簿属性,但我根本想不出任何优雅的东西......我认为简短的答案是这个问题并没有真正简短的优雅解决方案(如果有,我真的很想看看)。这是个坏消息。

好消息是我认为有种方法可以解决这个问题...1 稍微优雅一点,但需要您重新考虑您的一些方法,而另一种方法很脏,但可能更简单一些。

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

更脏的方式将涉及将整个工作簿本身变成一种“广告- hoc mutex”,通过
1) 将 WorkBookOpen 事件中的整个(原始)工作簿复制到 另一个 (temp) 工作簿中并使用temp 上的“SaveAs”方法将其放置在单独的位置。
2) 存储(原始)路径。
3) 将代码添加到检查 (temp) 的 WorkBook 打开事件和 A) 立即关闭并激活 temp 或 B) 用 ( temp),然后使用 SaveAs
4) 在用户保存 WorkBook 之前捕获事件并将其保存到 both original 位置,和 temp 位置。
5) 在 WorkBookClose 事件中,运行所需的任何清理并将 temp 保存回其原始位置。

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

我知道这很多,尤其是如果您不习惯使用 VBA;如果您希望我发布一些代码来帮助您完成任何这些步骤,请发表评论,我会的。

感谢您提出有趣的问题。

【讨论】:

  • 谢谢。复制到临时工作簿是一个有趣的想法,但我认为重新设计应用程序以消除对清理的依赖会更容易。在这种情况下没有触发 BeforeClose 事件对我来说似乎是一个错误。
  • NB 我从来没有真正保存工作簿(它是只读的),所以在我的情况下不需要保存临时和原始文件。
  • 是的,我会说至少 MSDN 文档应该说明您不能因此而依赖 BeforeClose 触发。我仍然很想看看是否还有其他人在这里提出了我们没有想到的创意。
  • 再次感谢。正如对问题的编辑中所述,我会将应用程序移动到 XLA 插件中(无论如何这可能是一个更好的解决方案)。
【解决方案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,但它在 之前的实例已经关闭之后调用。
  • 您是否有机会在工作簿打开而不是工作簿关闭时运行此代码?作为“一天的开始”过程还是什么?或者在工作簿关闭时设置一个标志,除非该标志存在,否则代码会在打开时运行?
  • 不,我无法在 Workbook_Open 上运行它。而且我不能在关闭时设置标志,因为工作簿是只读的。还是谢谢。
【解决方案3】:

您也可以通过以下方式抑制提示:

这将在没有警告的情况下重新打开一个打开的文件.. 但请注意,任何更改都会被丢弃!

Application.DisplayAlerts = False
Workbooks.Open (sPath)
Application.DisplayAlerts = True

来自Excel Forum

此解决方案满足我的需求

【讨论】:

    猜你喜欢
    • 2014-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多