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

时间:2010-03-29 09:28:14

标签: c# excel vsto excel-2007

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

这个想法是需要开发“某些东西”以防止使用关闭/保存工作簿,除非他/她检查了更新是否正确/准确。 numbers look correct动作纯粹是一种直观的练习,因此不会以任何方式编码。

简单的解决方案是在关闭特定工作簿之前提示用户验证数据是否已经过检查。

使用VSTO SE for Excel 2007,创建了一个加载项,该加载项挂钩到加载项WorkbookBeforeClose

中初始化的ThisAddIn_Startup事件
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建议您应该使用我认为正在执行的ThisApplication.WorkbookBeforeClose事件,因为它将跨越所有打开的文件。

我对该方法的问题是,假设我打开了多个文件,其中一些文件位于我的list中,该事件会阻止Excel按顺序关闭所有文件。现在需要单独关闭每个文件。 编辑 :当从“文件”菜单中使用退出Excel 时会发生这种情况。

问题

  1. 我是否正确使用WorkbookBeforeClose事件并且这是有效的&有效利用这一事件?
  2. 我应该使用应用程序级别事件或文档级别事件
  3. 上述行为是否正常
  4. 在加载项中使用工作簿事件时,欢迎使用任何其他建议
  5. 更新[2010年3月30日]:

    在修补时,我还尝试了以下尝试将BeforeClose事件处理程序绑定到按照上面链接建议打开的每个工作簿。

    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
    }
    

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

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

    更新[2010年4月7日]:

    格伦的建议答案很有用,但没有解决眼前的问题,因此我进一步澄清了最后一个问题。

    我还发现这个博客How to Get an Excel VSTO Workbook Closed Event与我的问题有些相关,因为它可以在我的解决方案的替代方法中使用,使用监视器类型的方法来处理工作簿(并且可能还使用新的介绍OnWorkbookClosed事件)。

    更新[2010年4月8日]:

    似乎有些混乱,我并不关心工作簿本身的任何验证,而是关注我使用的方法(即使用应用程序级WorkbookBeforeClose事件)是否正确。 @Mathias在下面的评论显示了对问题3的部分问题的正确理解,我认为这是默认的excel行为。解决此问题的解决方案是创建一个仅关闭我的特定文件的close函数。

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

    VS 2005与VSTO SE

3 个答案:

答案 0 :(得分:7)

应用程序级WorkbookBeforeClose是要使用的级别。问题是,在调用WorkbookBeforeClose时未保存文件会导致不稳定的行为。如果不是,则保存事件将启动,您现在已经有效地丢失了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

答案 1 :(得分:3)

由于您遇到了这种方法的问题,并且Excel可能无法让您执行所需的操作,也许您可​​以考虑另一种方法来解决整体问题。

根据某人是否验证了这些数字,您是否可以在工作簿中构建一些标记为“已验证/未验证”的内容?根据工作簿的实际使用方式(问题不清楚),将其显示为未验证的方式可能会有所不同......(可视)将背景颜色设置为浅红色,或者(编程)更改使用的命名范围指向空白区域,以便其他插件/宏不会找到数据。

要验证工作簿的用户需要单击按钮(在工作簿或工具栏中)以指示他们已对其进行了验证。然后,您的代码将撤消上述更改并设置一个标志,指示工作簿已经过验证。这可能是在本书某处的隐藏单元格中,也可能是在VBA模块的属性中。

要回顾......打开时,请检查标志。如果未设置,请将工作簿更改为未验证。如果已设置,则无需进行任何更改。当用户验证工作簿时,设置标志并永久保存。

希望这有帮助!

答案 2 :(得分:1)

  1. 我是否正确使用了WorkbookBeforeClose事件并且这是有效的&有效利用事件?

      

    我无法找到更好的事件。但是,我认为另一种方法是使用Save&Close函数使用WorkbookBeforeSave事件

  2. 我应该使用应用程序级别事件或文档级别事件吗?

      

    在撰写本文时,我会说是的。由于我无法使用我拥有的工具创建文档级加载项,因此这是最佳解决方案。有工具了吗?   可用,我会修改相关文件的_AssemblyName_AssemblyLocation文档属性。但是,我会通过使用模板然后根据需要保存文件来更改解决方案策略。此外,在保存之前,还没有完全探索,添加/删除正确的文档属性。文档级事件将非常适合使用上述方法。

  3. 上述行为是否正常?

      

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

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

      

    有关替代方法和不同事件的使用,请参阅上述答案。