【问题标题】:Prevent closing of workbook防止关闭工作簿
【发布时间】:2017-10-11 07:59:26
【问题描述】:

ABC.xls 文件有宏。现在,宏有一个 sub,当我按下 Ctrl + M 时,它会被调用。 该子程序将打开一个打开文件对话框,用户可以在其中选择一个CSV 文件。所以基本上,这个宏用于处理和保存CSV 文件。 下面是按下Ctrl + M 时调用的代码。

Sub runProperChangeSubroutine()             ' Assigned to shortcut key CTRL + M.
    file_name = ActiveWorkbook.Name         ' Gets the file name.
    Application.Run file_name & "!ChangeSub"
End Sub

当用户关闭工作簿时,我必须测试一个条件,比如CSV 中的每一行都有一个终止字符串。如果该终止字符串不是 目前,我应该向用户弹出一个消息框并防止关闭工作簿。 所以我做了以下...

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    Dim improperRowNumber As Integer
    Dim BlnEventState As Boolean
    improperRowNumber = returnImproperRow()

    BlnEventState = Application.EnableEvents
    Application.EnableEvents = True

    If improperRowNumber <> -1 Then
        Cancel = True
        MsgBox "The row number " & improperRowNumber & " is not ending with '@/#'. Please correct the row before closing."
    Else
        Call saveCSV
    End If
    Application.EnableEvents = BlnEventState
End Sub

单击关闭(右上角的 X 标记,关闭工作簿。我没有关闭 excel。)按钮,我可以看到消息框,但工作簿关闭。如果行没有正确结束,我希望用户进行一些编辑。 请提出建议。

编辑: 由于上面的代码不起作用,我在消息框后面使用ThisWorkbook.Saved = False如下图...

If improperRowNumber <> -1 Then
    MsgBox "The row number " & improperRowNumber & " is not ending with '@/#'. Please correct the row before closing."
    Application.DisplayAlerts = False
    ThisWorkbook.Saved = False
    Cancel = False
Else

现在它显示“Do you want to save the changes....”消息框。如果我点击消息框上的Cancel 按钮,工作簿不会关闭。

有没有办法自定义消息框文本或按钮或隐藏此Save 消息框?

【问题讨论】:

  • 您应该无法在 Workbook_BeforeClose 中使用 Cancel = True 关闭工作簿。也许你在子程序不正确的行号中有类似 EnableEvents = False 的东西?
  • 不,EnableEvents 语句不存在于不正确的RowNumber 子中。还有其他可能吗?
  • @MarcinSzalenec 禁用应用程序事件,msgbox 不会显示...但 OP 的处理程序显然正在运行。
  • FWIW 我似乎也无法取消关闭。谢谢,现在我会花几个小时研究 wtf 的进展,哈哈
  • 如果我在这里错了,请纠正我,但是既然您成功地可以检测到没有正确结尾的行('@/#'),为什么您的代码不能将它自己添加到该行?

标签: vba excel excel-2010


【解决方案1】:

如果您必须监视包含宏的工作簿以外的工作簿的关闭,您可以从启用宏的工作簿中拦截应用程序级事件,如下所示:

在 ThisWorkbook 后面添加(或改编)这段代码:

Option Explicit

Private m_CloseHelper As CloseHelper

Private Sub Workbook_Open()
    Set m_CloseHelper = New CloseHelper
End Sub

添加一个名为 CloseHelper 的新类模块:

Option Explicit

Private WithEvents m_App As Excel.Application

Private Sub Class_Initialize()
    Set m_App = Excel.Application
End Sub

Private Sub Class_Terminate()
    Set m_App = Nothing
End Sub

Private Sub m_App_WorkbookBeforeClose(ByVal Wb As Workbook, Cancel As Boolean)
    'Logic goes here, e.g. the code below will prevent the user from closing
    'any workbook other than this one, for as long as this workbook is open.
    If Not Wb Is ThisWorkbook Then
        Cancel = True
        MsgBox "Hello from m_App_WorkbookBeforeClose"
    End If
End Sub

重要的关键字是 WithEvents,其原理是 Excel 应用程序引发的事件现在可以在 CloseHelper 类中进行编码。

您可以在此处找到更深入的文章:Application Events

【讨论】:

    【解决方案2】:

    按下右上角的 X 按钮退出 Excel 应用程序。您不应该期望工作簿在应用程序关闭时保持打开状态。您可以编写一个应用程序事件过程来阻止 Excel 退出,但更好的方法可能是简单地改掉使用该按钮的坏习惯。找到另一种关闭工作簿的方法。

    【讨论】:

    • 右上角,我的意思是关闭工作簿,我没有关闭excel。我将编辑帖子。谢谢。
    • 坦率地说,我怀疑工作簿是否正在使用 File -> Close 关闭,MsgBox 出现,工作簿仍然关闭。如果它真的在这种情况下关闭,则该操作应该源自一些其他意外运行的代码。但是,如果你真的面临 Excel 应用程序的故障,或者如果你无法控制人们如何关闭工作簿,那么接下来要尝试的是利用应用程序事件(现在你使用的是工作簿事件)来携带你已经有相同的测试。因此我相信我的回答仍然有效。
    • 我认为关闭工作簿或关闭 Excel 并不重要。调用 Workbook_BeforeClose 的两种方式。
    • 这是一个顺序问题。当您退出 Excel 时 (1) 打开的工作簿被关闭,(2) 工作簿的关闭被成功阻止,(3) Excel 在不关闭该工作簿的情况下无法退出,(4) Excel 决定它不想挂起由于代码和用户指令之间的差异,(5) Excel 强制关闭工作簿,(6) Excel 被卸载。故事的寓意:不要给出相互矛盾的指示。在此处了解应用程序事件的编程:- cpearson.com/excel/appevent.aspx
    【解决方案3】:

    Workbook_BeforeClose 事件仅适用于代码所在的工作簿。它在您尝试关闭宏工作簿并将其参数 Cancel 设置为 TRUE 时运行,仅在您关闭 Excel 时取消宏工作簿的关闭。打开的 csv 文件是一个单独的工作簿,Excel 会尝试单独关闭它,从而生成一条关于保存 csv 文件的单独消息。

    要自动防止 csv 文件被关闭,您需要使用可扩展性编程在 csv 文件在 Excel 中打开时将 Workbook_BeforeClose 事件添加到该文件。显然,您无法保存带有事件的文件,但您不需要。模块中的代码将在工作簿仍处于打开状态时运行,以防止在不满足条件时关闭; 满足条件后允许的成功保存将采用 .csv 格式,该格式将擦除临时添加的代码。

    http://www.cpearson.com/excel/vbe.aspx

    【讨论】:

      【解决方案4】:

      您是否尝试过关闭所有加载项(或在安全模式下运行 Excel)?

      我之所以问这个问题,是因为您的加载项之一包含 应用程序级别事件,就像 Excelosaurus 的答案中描述的那样。它可能包含Application.EnableEvents = False 甚至Cancel = False 并干扰您的代码。

      编辑:使用受保护的加载项尤其难以检测到这一点,因为代码将在 Workbook_BeforeClose 之后运行,即使您是,您也无法知道它在做什么使用 F8 逐行调试。

      【讨论】:

      • 如果事件被禁用,Workbook_BeforeClose 事件根本不会运行。
      • 应用程序级别事件在工作簿级别事件之后运行,因此即使应用程序级别的事件禁用事件,工作簿级别事件也将始终运行。
      • (当然,只要在按下 X 按钮之前启用事件。)
      • 抱歉,我的意思是,由于 OP 指示工作簿事件中的某些代码正在运行,Application.EnableEvents = False 不可能是问题的根源 - 它会停止一切。这会很奇怪,但理论上加载项可以设置Cancel = False
      • 您也可以这样:Application.EnableEvents = False Wb.Close SaveChanges:=False Application.EnableEvents = True 这将阻止 Workbook_BeforeClose 运行 second 时间。
      【解决方案5】:

      您可以在工作簿宏中使用此代码

      Private Sub Workbook_BeforeClose(Cancel As Boolean)
      ActiveWorkbook.Save
      Workbooks.Open Application.ActiveWorkbook.FullName
      End Sub
      

      如您所见,它基本上会在关闭时保存并打开工作簿

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-02
        相关资源
        最近更新 更多