粘贴多个值时出现错误的原因是,如果Target 超过一个单元格,则Target.Value 返回一个数组,并且您无法将数组与字符串进行比较。这就是“类型不匹配”的意思。 Target.Value (Array) 的类型 Target.Value = "" 中"" (String) 的类型。
要解决问题,您可以尝试用Target.Cells(1).Value 替换出现的Target.Value,但您的代码仍然无法正常工作,因为还有更多未解决的相关问题以及其他问题不相关的问题:
这个 sub 甚至不应该运行。
你误解了Worksheet_Change(ByVal Target As Range) 是什么。它是一个事件处理程序,每次任何工作表中的单元格被修改或删除时都会自动运行。 (从技术上讲,一个单元格可以被“清除”或“删除”,两者之间存在细微差别。)
Target 是已更改的单元格范围。它可以是一个细胞或多个细胞。您需要专门检查Target 是否与您感兴趣的单元格范围匹配并排除所有其他单元格。要检查已删除(又名“清除”)的单元格,您需要检查单元格内容是否为空白。检查真正的删除有点复杂。
我可以将 _Change 更改为 _OnDelete 或类似的东西吗? *
不,没有“删除”事件。如上所述,可以从“更改”事件中检测到删除。要查看可用事件列表,请在代码窗口顶部的左侧下拉列表中选择“WorkSheet”,然后单击右侧的下拉列表。
我以为我的代码在说,“当 B 列中大于第 1 行(标题行)的单元格被删除时,运行其余代码”*
不完全是。
- 只有在单个单元格被删除时才能正常运行。多个删除的单元格将导致与上述相同的错误。
-
DeleteRows (ProjectName) 位于 IF 块之外,因此它始终在任何任何单元格更改时运行。幸运的是,ProjectName 在除 B 列(不包括标题)之外的所有情况下都是空白的,因此实际上没有删除任何内容。
为了解决所有问题,我已将您的代码更新为更强大的版本(以及一些更漂亮的消息框):
Private Sub Worksheet_Change(ByVal Target As Range) ' Runs every time ANY cell in the sheet is modified , cleared or deleted
'v0.1.1
Dim rngClippedTarget As Range
Set rngClippedTarget = Intersect(Target, Columns(2).Resize(Rows.Count - 1).Offset(1)) ' Extract the 2nd column, row 2 downwards, cells from Target (if any)
If rngClippedTarget Is Nothing Then Exit Sub 'Ignore changes if there are none in column 2 (excluding header row)
If rngClippedTarget.Cells(1).Value2 <> vbNullString Then Exit Sub ' Ignore changes if the first changed cell in column 2 has not been "emptied"
With Application
.EnableEvents = False ' Otherwise, the Worksheet_Change event is re-triggered by the .Undo
.Undo ' Restore cleared values
.EnableEvents = True
End With
Dim lngCellCount As Long
lngCellCount = rngClippedTarget.Cells.Count
Dim strConfirmMsg As String
strConfirmMsg _
= rngClippedTarget.Cells(1).Value2 _
& IIf(lngCellCount = 1, "", " and " & lngCellCount - 1 & " other project" & IIf(lngCellCount = 2, "", "s")) _
& " will be deleted." & vbCrLf _
& "Are you sure? (This cannot be undone!)"
If vbCancel = MsgBox(strConfirmMsg, vbCritical + vbOKCancel) Then Exit Sub 'Abort with all changes reverted
Dim rngCell As Range
For Each rngCell In rngClippedTarget
DeleteRows rngCell.Value2 ' Delete the appropriate Database rows
Next rngCell
With Application
.EnableEvents = False ' Otherwise, the Worksheet_Change event is re-triggered by the .Delete
rngClippedTarget.EntireRow.Delete ' Delete all the changed rows in the sheet
.EnableEvents = True
End With
MsgBox lngCellCount & " project" & IIf(lngCellCount = 1, " has", "s have") & " been deleted.", vbInformation
End Sub
注意事项:
- 允许粘贴多个值而不会出错。
- 允许一次性删除多个项目。如果不希望这样做,可以将其更改为提醒用户并中止。
- 修复了取消删除未恢复已删除项目名称的问题。
- 使用
vbOKCancel 代替vbYesNo 允许按Esc 中止删除。
- 使用
.Value2 代替Value 更快,并且可以避免潜在的问题,因为不执行隐式类型转换。
- 使用RVBA Naming Conventions。
注意事项:
- 如果用户实际删除工作表或表格行,则不起作用。删除工作表或表格行的 contents 可以正常工作。 (可以更新代码以允许实际删除,但有点复杂)
- 如果删除了一个已经为空的单元格,它会尝试删除一个名为“”的项目。
- 不会忽略表格下方“项目名称”(
B) 列中的单元格,因此如果用户删除了此处的单元格,则上一点适用。
- 对于多个项目删除,它假定如果第一个项目名称为空,则其余项目名称也是如此。因此,如果用户将多个值粘贴到
B 列中的现有值之上,并且只有第一个粘贴的值是空白的,所有这些预先存在的项目将被删除,而不仅仅是第一个。
* 来自已删除的 cmets