【问题标题】:Excel VBA: Save As triggers Change event in ComboBoxExcel VBA:另存为触发组合框中的更改事件
【发布时间】:2010-08-25 16:58:21
【问题描述】:

我有一个 Excel 工作簿,其中包含一些直接放置在工作表上的 ComboBox 控件。这些是表单工具栏中的标准组合框。

当用户使用“另存为”以不同的名称保存工作簿时,这会触发所有组合框上的 Change 事件,包括未激活的工作表上的组合框。这似乎不合理,因为选择实际上并没有改变。由于事件处理程序中的代码,这会导致各种不良行为。简单的“保存”不会触发该事件。

Google suggests 这是 Excel 中的一个已知问题。 rumours 是由使用命名范围作为组合框的 ListFillRange 引起的,尽管它不是易失性名称,但我已经这样做了。我正在寻找一种通过对代码和电子表格进行最小更改来防止这种情况发生的方法。有人有经过验证的解决方案吗?

【问题讨论】:

  • 我无法使用 Excel 2007 重现此行为,既不使用正常范围,也不使用命名范围。也许你应该上传一个例子......
  • @belisarius 我无法上传完整的工作簿,因为它包含大量专有代码。我现在没有时间尝试制作一个小例子:(
  • 无法在 Excel 2003 中确认。您能否确认您使用的是“表单”控件而不是“控件”控件? (该死,微软!)Forms 控件没有Change 事件或ListFillRange 之类的属性。

标签: excel vba


【解决方案1】:

我在一个只有一张工作表 Sheet1 的新工作簿中执行了以下操作,它似乎可以在保存之前禁用事件,然后在之后重新启用它们。它应该通过模仿AfterSave 事件绕过您看到的问题。这是我在 Sheet1 上的事件代码(也可以是 OLEObject 代码)

Option Explicit

Private Sub Worksheet_Change(ByVal Target As Range)
  MsgBox Target.Address & ": " & Target.Value
End Sub

这是我的 ThisWorkbook 代码

Option Explicit

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)

  ' To see the change code work before disabling
  ' Should show a message box
  Sheet1.Range("A1") = "Before After Events Off"

  Application.EnableEvents = False
  Application.OnTime Now, "ThisWorkbook.Workbook_AfterSave"

  ' This time it will not show a message box
  ' You will never see this one . . . 
  Sheet1.Range("A1") = "After After Events Off"

End Sub

Private Sub Workbook_AfterSave()
  Application.EnableEvents = True
End Sub

.OnTime 方法将 AfterSave“事件”扔到执行队列中。有效!

【讨论】:

    【解决方案2】:

    您可以在工作簿的 BeforeSave 事件中设置一个标志,然后在处理每个组合框中的更改事件之前检查该标志。似乎没有 AfterSave 事件,因此您需要在组合框更改事件中检查该标志后清除该标志。该标志需要不仅仅是一个简单的布尔值,因为在处理所有组合框更改事件之前它无法关闭。下面是一些示例代码:

    Public ComboBoxChangeCounter As Integer
    
    Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
        Const NumOfComboBoxChangeEvents As Integer = 5
        ComboBoxChangeCounter = NumOfComboBoxChangeEvents
    End Sub
    
    Function JustSaved() As Boolean
        If ComboBoxChangeCounter > 0 Then
            ComboBoxChangeCounter = ComboBoxChangeCounter - 1
            JustSaved = True
        End If
    End Function
    
    Private Sub Combo1_Change()
        If JustSaved Then Exit Sub
        'Your existing code '
        ' ... '
        ' ... '
        ' ... '
    End Sub
    

    我将组合框更改事件的数量设置为常数,但您可能有一些方法可以通过编程方式确定该数字。此解决方法确实需要为每个组合框更改事件添加代码,但它应该很简单,因为您需要做的就是在每个事件的开头复制并粘贴 If JustSaved Then Exit Sub 行。

    此解决方法假定将在组合框更改事件之前调用 Workbook BeforeSave 事件。我不知道事实是不是这样。

    【讨论】:

    • 这不是一个坏主意,但这意味着您必须知道将在 SaveAs 上引发更改事件的 OLEObject 的数量。此外,您对 Const 的使用是非正统的;不应更改常数。此解决方案依赖于错误代码的未记录功能。不能保证它是可靠的。必然会发生一些真正的事件会被错过。
    猜你喜欢
    • 2019-05-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-28
    • 2021-02-15
    • 2017-03-12
    • 1970-01-01
    • 2015-06-23
    • 2010-09-15
    相关资源
    最近更新 更多