Excel VBA:另存为触发ComboBox中的Change事件

7
我有一个包含一些直接放置在工作表上的ComboBox控件的Excel工作簿。这些是来自“表单”工具栏的标准组合框。
当用户使用“另存为”将工作簿保存为不同的名称时,这会触发所有组合框(包括非活动工作表上的组合框)的更改事件。这似乎是不合理的,因为选择实际上并没有改变。由于事件处理程序中的代码,这会导致各种不良行为。简单的“保存”不会触发该事件。

谷歌建议,这是Excel中已知的问题。有传言称,这是由于将命名范围用作组合框的ListFillRange而引起的,尽管它不是一个易变的名称。我正在寻找一种方法,以最小的代码和电子表格更改来防止这种情况发生。有没有人有经过验证的解决方案?


3
我无法在Excel 2007中复制这种行为,无论是使用普通范围还是使用命名范围。也许你应该上传一个例子... - Dr. belisarius
@belisarius 我无法上传完整的工作簿,因为它包含大量专有代码。我现在没有时间尝试制作一个小例子 :( - MarkJ
1
无法在Excel 2003中确认。您能否确认您正在使用“表单”控件而不是“控件”控件?(该死的微软!)表单控件没有“更改”事件或像“ListFillRange”这样的属性。 - Lunatik
2个回答

3

我在一个只有一个工作表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到每个事件的开头。
这种解决方法假定工作簿BeforeSave事件将在下拉框更改事件之前被调用。我不知道是否确实如此。

这不是一个坏主意,但这意味着你必须知道在SaveAs时会抛出更改事件的OLEObjects数量。此外,您对Const的使用是非正统的;常量不应更改。这个解决方案依赖于有缺陷代码的未记录特性。不能保证它是可靠的。肯定会错过一些真正的事件。 - adamleerich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接