如何正确有效地使用WorkbookBeforeClose事件?

每天,一个人需要检查具体的工作簿是否已经根据彭博和路透市场数据正确更新; 即所有数据都已经通过,数字看起来是正确的。 过去,人们并没有检查导致上传到其他系统的“数字”。

这个想法是,需要开发一些“东西”,以防止使用者closures/保存工作簿,除非他/她检查了更新是正确的/准确的。 numbers look correct行为纯粹是一个直观的练习,因此将不会被编码。

简单的解决scheme是在closures特定工作簿之前提示用户以validation数据已被检查。

使用VSTO SE for Excel 2007,创build了一个加载项,该加载项挂接到在加载项ThisAddIn_Startup初始化的WorkbookBeforeClose事件

 private void wb_BeforeClose(Xl.Workbook wb, ref bool cancel) { //.... snip ... if (list.Contains(wb.Name)) { DailogResult result = MessageBox.Show("some message", "sometitle", MessageBoxButtons.YesNo); if (result != DialogResult.Yes) { cancel = true; // i think this prevents the whole application from closing } } } 

我发现以下ThisApplication.WorkbookBeforeSave vs ThisWorkbook.Application.WorkbookBeforeSave其中build议应该使用ThisApplication.WorkbookBeforeClose事件,我认为是我在做什么,因为将跨越所有打开的文件。

我使用这种方法的问题是,假设我打开了几个文件,其中一些在我的list ,这个事件阻止了Excel顺序closures所有文件。 现在要求每个文件分别closures。 编辑 :这发生在退出Excel从文件菜单中使用。

问题

  1. 我是否正确使用WorkbookBeforeClose事件,是否有效地使用事件?
  2. 我应该使用应用程序级事件还是文档级事件
  3. 上述行为是否正常
  4. 在加载项中使用工作簿事件时,欢迎任何其他build议

更新[2010年3月30日]:

摆弄,我也尝试了下面的尝试绑定BeforeClose事件处理程序的每个工作簿打开,如上面的链接build议。

 private void ThisAddIn_Startup(...) { // snip Globals.ThisAddin.Application.WorkbookOpen += Application_Open; } private void Application_Open(XL.Workbook wb) { wb.BeforeClose += Document_WorkbookBeforeClose; // method does the same as above } 

我用这种方法发现的问题是,我尝试closures所有Excel文件(使用退出Excel选项)事件处理程序不执行。 从我的观察,当要检查的文档不是活动文档时,会发生这种情况。

与我最初的方法相比,这种方法似乎不稳定。 每次打开文档时,我不确定或感到舒服的一件事是约束事件。

更新[2010年04月07日]:

格伦build议的答案是有用的,但是没有解决眼前的问题,因此我最后再澄清一点。

我也发现这个博客如何获得一个Excel VSTO工作簿封闭事件是有点相关我的问题,因为它可以在我的解决scheme的替代方法中使用监视器types的方法来处理工作簿(也可能使用新引入的OnWorkbookClosed事件)。

更新[08-Apr-2010]:

似乎有一些混淆,我不关心工作簿本身的任何validation,而是我正在使用的方法(即使用应用程序级别的WorkbookBeforeClose事件)是否正确。 下面的@Mathias的注释显示了与问题3有关的部分问题的正确理解,我认为这是默认的excel行为。 克服这个问题的解决scheme是创build一个closures函数,只closures我的特定文件。

  1. 上述行为是否正常是的,但是为什么? 由于插件挂接到应用程序级别的事件中,事件的检查和取消会阻止应用程序closures任何其他工作簿。 这里的关键是ref bool cancel参数( cancel=false允许正常closures工作簿(默认), cancel=true可防止工作簿closures)

VS 2005与VSTO SE

应用程序级别的WorkbookBeforeClose是要使用的。 问题在于,当调用WorkbookBeforeClose时文件没有被保存,导致不规则的行为。 如果不是这样,Save事件将会启动,并且现在已经有效地丢失了WorkbookBeforeClose事件,因为它已经发生了。 这里有一些帮助解决这个问题的VBA代码。

 Private Sub Workbook_BeforeClose(Cancel As Boolean) If Not Me.Saved Then NotSavedPrompt = Me.Name & " has not been saved. Would you like to save now?" SaveYesNo = MsgBox(NotSavedPrompt, vbQuestion + vbYesNoCancel) Select Case SaveYesNo Case vbYes Me.Save Case vbNo Me.Saved = True Case vbCancel Cancel = True Exit Sub End Select End If Call MyRoutine() //'this should be your sub that does what you want End Sub 

既然你遇到了这种方法的问题,Excel可能不会让你做你所需要的,也许你可以考虑另一种方法来解决整体问题。

您可以根据是否有人validation了这些数字,将其标记为“已validation/未validation”的工作簿。 根据工作簿的实际使用方式(不清楚问题),将其显示为未validation的方式可能会有所不同(可视化)将背景颜色设置为浅色的红色,或者(编程式)将使用的名称范围指向一个空白区域,以便其他插件/macros不会find数据。

要validation工作簿的用户需要单击button(在工作簿或工具栏中)以指示他们已经validation了它。 您的代码将撤消上述更改并设置一个标志,指示该工作簿已被validation。 这可能在本书某处的隐藏单元中,或VBA模块的属性中。

回顾…打开,检查国旗。 如果未设置,请将工作簿更改为未validation。 如果已设置,则不需要更改。 当用户validation工作簿时,设置标志并永久保存。

希望这可以帮助!

  1. 我是否正确使用WorkbookBeforeClose事件,是否有效地使用事件?

    我无法find更好的事件来使用。 不过,我认为另一种方法是使用WorkbookBeforeSave事件的Save&Close函数

  2. 我应该使用应用程序级事件还是文档级事件

    在写这篇文章时,我会说是的。 由于我无法使用我拥有的工具创build文档级外接程序,因此这是可用的最佳解决scheme。 如果工具可用,我将修改相关文件的_AssemblyName_AssemblyLocation文档属性。 但是,我将通过使用模板并根据需要保存文件来更改解决scheme策略。 另外在保存之前,还没有完全探索这个,要添加/删除正确的文件属性。 文档级事件将非常适合使用上述方法。

  3. 上述行为是否正常?

    是的,但是为什么? 由于插件挂接到应用程序级别的事件中,事件的检查和取消会阻止应用程序closures任何其他工作簿。 这里的关键是ref bool取消参数(取消= false允许正常closures工作簿(默认),取消= true可防止工作簿closures)。 如果我在这里错了,请告诉我。

  4. 在加载项中使用工作簿事件时,欢迎任何其他build议

    请参阅上述答案,了解其他方法和使用不同的事件。