Worksheet_Change 事件中的目标范围不正确

Incorrect target range in Worksheet_Change event

我是一名 Excel-VBA 新手,我正在尝试编写一小段代码,该代码由更改作品中单元格值的人触发sheet。如果 changed 单元格的值小于零,它应该将其设置为零。代码如下所示:

Private Sub Worksheet_Change(ByVal Target As Range)
'Debug.Print Target.Address
 If Target.Column = 6 Then
  For Each Cell In Target.SpecialCells(xlCellTypeConstants, 3)
     If Cell.Value < 0 Then
        Cell.Value = 0
     End If
  Next
 End If
End Sub

现在发生的情况是,当我更改第 6 列中任何单元格的值时,sheet 中包含小于零的数字的每个单元格 更改为零。

我在想为 Worksheet_Change 事件处理程序创建的 "Target" 对象将仅包含更改的 cell/cells,因此我的代码只会更改单元格的值首先被修改并触发了事件。

我试图通过使用 Debug.Print 输出对象的地址来帮助自己。它打印出 sheet 中每个单元格的地址,其值小于零,因此我多次假设处理程序 运行。

我实际上找到了问题本身的解决方法,但我的问题是:我是如何在使用 Worksheet_Change 事件时失败的?将来我该怎么做才能避免此类问题?

有效(已更新

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim c As Range
    For Each c In Target
        If c.Column = 6 Then If IsNumeric(c) Then If c < 0 Then c = 0
    Next c
End Sub

请学习并使用 OPTION EXPLICIT !

编辑 1: 使用评论中建议的错误修复更新了代码

编辑 2: 更新了带有错误处理的代码以处理数组公式

回答你的问题

[1] how did I fail in using the Worksheet_Change event and [2] what can I do in the future to not have such problems?

  1. 从技术上讲你没有
  2. 对于此类问题没有任何帮助,尽管以下规则通常有帮助

你对Target对象的理解是正确的。您的代码失败,因为 SpecialCells 不喜欢对单个单元格进行操作。给它一个,它会扩展到 整个 sheet!给它任何其他东西,它工作得很好。

您的 Debug.Print 显示所有单元格的原因是每次您的代码更改单元格时,另一个 更改事件被触发。幸运的是,第二个找到了一个零,因此它不会触发 另一个。以下一般规则应该有助于避免很多问题,但不是这个特定的问题:

  • 始终用 Application.EnableEvents.
  • 将更改工作簿任何部分的事件处理程序中的任何代码括起来

要修复代码使其正常工作,只需删除 SpecialCells 方法调用即可。由于您使用的是 Cell.Value 而不是强烈推荐的 Cell.Value2(请参阅 ),因此 VBA 隐式类型会为您将格式化为文本的数字转换为实际数字。因此,该代码适用于数字和文本值。

代码:

Private Sub Worksheet_Change(ByVal Target As Range)
  'Debug.Print Target.Address;
  Application.EnableEvents = False
    For Each Cell In Target '.SpecialCells(xlCellTypeConstants, 3)
      If Cell.Column = 6 And Cell.Value < 0 Then
        On Error GoTo Error:
        Cell.Value = 0
        On Error GoTo 0
      End If
    Next
GoTo ExitSub:
Error:
  If Err.Number = 1004 Then ' 1004 -> "You cannot change part of an array."
    'Application.Undo ' Uncomment to disallow array entering a negative value formula into/across column 6
    MsgBox "A cell could not be zeroed as" & vbCr & "it is part of an array formula.", vbExclamation, "Microsoft Office Excel"
    On Error GoTo 0
  Else
    On Error GoTo 0
    Resume
  End If
ExitSub:
  Application.EnableEvents = True
End Sub

备注:

- 更新 1:代码现在可以正确处理多单元更改。

- 更新 2:代码现在捕获错误 1004 以处理输入数组公式。它可以允许输入数组公式导致第 6 列中出现负值,或者完全停止输入。

我来这里是为了寻找一种方法来停止我的工作sheet 从 "flashing" 因为它 运行 代码格式化列和行,因为用户在 sheet,包括过滤器和排序。

此外,根据对 OP 问题的官方回答,如果您试图控制 Worksheet_Change() 事件完全不触发 (它仍会触发,但您可以绕过它),例如,在您希望用户更改数据但不更改数据周围区域(例如作为 VBA 系统一部分的字段或标签)的情况下,我使用 Target.Row 元素确定我的极限。与 Target.Column 相结合,您可以专注于用户可以自由控制的特定单元格。

Dim myTopLimit AS Integer
myTopLimit = 6
etc..etc
if Target.Row < myTopLimit and Target.Row > myBottomLimit and Target.Column < myLeftLimit and Target.Column > myRightLimit then
.... code to allow WorkSheet_Change() to do somthing
else
.... code to force WorkSheet_Change() to drop through or no code
End If