Excel VBA的bug /exception – ActiveWorkbook.Save改变Workbook_BeforeSavefunction

在我的代码中,我使用了Workbook_BeforeSave函数来执行一些文本格式。

当我点击保存button时,它运行并格式化一些单元格的大小和字体types。
这是我的代码的一部分,这个工作:

 Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) Dim c As Range Dim rng As Range Set rng = ActiveSheet.UsedRange.Cells For Each c In rng If ispcname(c.Value) = True Or isip(c.Value) = True Then ActiveSheet.Hyperlinks.Add Anchor:=c, Address:="": c.HorizontalAlignment = xlCenter: c = StrConv(c, vbProperCase): c.Font.Name = "Arial": c.Font.Size = "10" If Right(c, 1) = "$" Then y = c.Column: x = c.Row Dim i As Integer For i = 1 To rng.Rows.Count If LCase(Cells(i, y).Value) = "backup" Then If Right(c, 1) = "$" Then Cells(x, y) = Cells(x, y - 2) & "$": ActiveSheet.Hyperlinks.Add Anchor:=c, Address:="": c.Font.Name = "Calibri": c.Font.Size = "10": c.HorizontalAlignment = xlCenter: c.Font.Color = RGB(192, 0, 0) End If Next i End If Next c End Sub 

我最近实现了一个代码,如果它closures,将保存工作簿。

 Private Sub Workbook_BeforeClose(Cancel As Boolean) Application.DisplayAlerts = False ActiveWorkbook.Save Application.DisplayAlerts = True End Sub 

然后出现了一些我无法解释的错误。 当ActiveWorkbook.Save运行时,应该更改为Calibri的单元格改为Arial ,大小保持不变,颜色正常工作。 但是,当我手动点击保存button,它应该像它应该。 (将单元格更改回Calibri

没有其他代码会干扰,因为当我注释到将字体types更改为CalibriActiveWorkbook.Save也停止将其更改为Arial

我的问题是:

  • 为什么发生这种情况? 这是一个错误?
  • 有没有解决办法?

我正在使用Excel 2007。

不知道为什么会发生这种情况,但是一种解决方法似乎是手动调用Workbook_BeforeSave ,然后为ActiveWorkbook.Save调用禁用它:

 Private Sub Workbook_BeforeClose(Cancel As Boolean) Application.DisplayAlerts = False Application.EnableEvents = False Workbook_BeforeSave False, False 'Manual call. Me.Save 'Save without the event firing again. Application.EnableEvents = True Application.DisplayAlerts = True End Sub 

也就是说,在Workbook_BeforeSave处理程序中也有一些好奇的逻辑。 首先,我不认为For i = 1 To rng.Rows.Count正在做你认为正在做的事情。 它不一定会遍历整个列,因为UsedRange.Cells不必在第1行开始。如果您使用的范围类似于$A$4:$Z$100rng.Rows.Count将是97并且所有对Cells(i, y)引用都将被closures3。

ispcname(c.Value) = True Or isip(c.Value) = TrueRight(c, 1) = "$"是互斥的也不清楚。 如果是的话, If Right(c, 1) = "$"实际上应该是ElseIf

结合其他东西:

  1. 在一行中执行5个不同的语句If语句非常难以阅读,并且容易出错。 使用实际If...End If块,除非行动是像Exit Sub小事琐碎。
  2. 第二个If Right(c, 1) = "$" Then总是如此。 它可以完全删除。
  3. 在以一种可读的方式实际地格式化你的代码之后,很明显你在For Each c In rng循环中遍布整个地方使用c属性。 我把它放在一个With块。
  4. 你只需要使用ActiveSheet一次。 之后,你可以从rng.Parent得到它,或者(更好的)获得它的参考。
  5. 当你需要一个String时,习惯使用String返回函数而不是Variant返回函数。 即Right$而不是Right – 后者进行隐式投射。
  6. 完全限定您对Cells所有引用。
  7. 避免隐式使用对象的默认属性,即Range.Value
  8. 使用Long行计数器,而不是Integer以避免溢出的可能性。
  9. 使用vbNullString而不是文字""
  10. Font.Size以点为单位。 它应该是一个数字,而不是一个string。

它应该看起来更像这样:

 Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) Dim c As Range Dim sh As Worksheet Set sh = ActiveSheet 'Tip 4 Dim rng As Range Set rng = sh.UsedRange.Cells For Each c In rng With c 'Tip 3 If ispcname(.Value) Or isip(.Value) Then 'Tip 1 sh.Hyperlinks.Add Anchor:=c, Address:=vbNullString 'Tips 4 and 9 .HorizontalAlignment = xlCenter .Value = StrConv(.Value, vbProperCase) 'Tip 7 .Font.Name = "Arial" .Font.Size = 10 'Tip 10 End If 'Pretty sure this should be an ElseIf structure here. If Right$(.Value, 1) = "$" Then 'Tips 5 and 7. y = .Column x = .Row Dim i As Long 'Tip 8 For i = 1 To rng.Rows.Count 'This is most likely wrong. 'Tip 2 used to be here. If LCase$(sh.Cells(i, y).Value) = "backup" Then 'Tips 1, 5, and 6 .Value = sh.Cells(x, y - 2).Value & "$" 'Tips 4, 6, and 7 sh.Hyperlinks.Add Anchor:=c, Address:=vbNullString 'Tips 4 and 9 .Font.Name = "Calibri" .Font.Size = 10 'Tip 10 .HorizontalAlignment = xlCenter .Font.Color = RGB(192, 0, 0) End If Next i End If End With Next c End Sub 

如果您使用“$”来表示单元格是货币,则不要testing最后一个字符是否为“$”。 你必须检查单元是否有货币格式。

修改该行

 if right(c,1)= "$" 

 fc = c.NumberFormat If InStr(1, c, "$") = 0 Then ... 

你的testing将永远不会在c中find“$”。