2010-08-25 88 views
7

我有一个Excel工作簿,其中包含直接放置在工作表上的一些ComboBox控件。这些是窗体工具栏中的标准组合框。Excel VBA:另存为触发器在组合框中更改事件

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

Google suggests这是Excel中的一个已知问题。有rumours它是由使用命名范围作为ListFillRange组合框,我已经完成,虽然它不是一个易变的名称。我正在寻找一种方法来防止这种情况发生,只需对代码和电子表格进行最小限度的更改。有没有人有成熟的解决方案?

+3

我无法使用Excel 2007重现此行为,既不使用正常范围也不使用命名范围。也许你应该上传一个例子... – 2010-08-26 15:24:23

+0

@belisarius我不能上传完整的工作簿,因为它包含了很多专有代码。我现在没有时间来尝试生成一个小例子:( – MarkJ 2010-08-26 15:27:04

+1

无法在Excel 2003中确认。您能否确认您使用“Forms”控件而不是“erm”“Controls”控件?该死的你,微软!)Forms控件没有'Change'事件或像ListFillRange这样的属性 – Lunatik 2010-08-27 10:15:54

回答

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事件将在组合框更改事件之前被调用。如果是这样,我不知道事实。

+0

这不是一个坏主意,但它意味着你必须知道会引起改变的OLEObjects的数量另外,你使用Const是非正统的,一个常量不应该改变,这个解决方案依赖于一个没有记录的bug代码的特性,不能保证它是可靠的。 _bona fide_事件将被错过。 – adamleerich 2011-09-06 19:26:29

3

我在一个新工作簿中仅使用一张工作表Sheet1完成了以下工作,它似乎可用于在保存之前对事件进行diable,然后重新启用它们。它应该绕过通过模仿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“事件”到执行队列。有用!