Вопрос

thanks in advance for any clarity you can offer.

In an Excel Workbook with many modules and worksheets, at the bottom of the VBA code for SHEET2, there is this Subroutine:

Private Sub Worksheet_Change(ByVal Target As Range)

Dim TargetCells As Range

Set TargetCells = Range("B1000:B1029")

If Not Application.Intersect(TargetCells, Range(Target.Address)) Is Nothing Then
   Call SpecificSubRoutine
End If

End Sub

My understanding of this code is that it watches the entire sheet for ANY changes. If ANYTHING is changed, anywhere on the sheet, it runs the If statement. The If statement fails in the event that any of the changes made to the sheet take place outside of the specified TargetCells range, but this Sub still tries to validate the If statement EVERY time ANYTHING is changed on the sheet.

Now, you might be able to guess that my problem is some stack overflow. (Run-time error '28': Out of Stack Space)

Whenever the Worksheet_Change Sub runs, if the changes to the sheet were made inside of the TargetCells range, it calls SpecificSubRoutine which populates cells, which triggers the Worksheet_Change Sub for every time SpecificSubRoutine populates ANY cell. (SpecificSubRoutine also calls different modules, which of course populate cells, which of course trigger the Worksheet_Change Sub)

Not so good.

Also, most of the subroutines throughout the application are wrapped in Application.ScreenUpdating = False / Application.ScreenUpdating = True, which I mistakenly thought would limit the number of times Worksheet_Change is called to once, immediately after Application.ScreenUpdating = True runs.

NOTE OF IMPORTANCE: Neither SpecificSubRoutine nor any of the Subroutines called by it populate cells in the TargetCells range. I'm not quite that dim...

Here are my questions:

  1. Is there a way to narrow the scope of what triggers the Worksheet_Change Sub, so that only changes in the TargetCells range triggers it? (instead of changes anywhere in the sheet)
  2. Is there a way to do what I mistakenly thought that Application.ScreenUpdating would do? (make changes to the sheet all in one bulk update, as opposed to triggering a change with nearly every step)
  3. Also, as an extra curiosity, is there a way to have Worksheet_Change watch 2 specific ranges (instead of the whole sheet?) Knowing how to do this would be paramount, and would likely solve all of the problems on this sheet.

My intuition is to add an End to the last part of SpecificSubRoutine, or to the end of any/all of the Subroutines called by it, but I'm just not sure this will circumvent the looping through Worksheet_Change multiple times, since Application.ScreenUpdating doesn't bulk update like I thought.

Ideas?

Это было полезно?

Решение

Part 1: No - the event handler responds to all changes on the sheet: any filtering in how you respond to that change must occur in the handler itself.

Part 2: answered by @simoco

Part 3 (and incorporating simoco's suggestion):

Private Sub Worksheet_Change(ByVal Target As Range)

    Application.EnableEvents=False

    If Not Application.Intersect(Me.Range("B1000:B1029"), Target) Is Nothing Then
       Call SpecificSubRoutine
    End If

    If Not Application.Intersect(Me.Range("D1000:D1029"), Target) Is Nothing Then
       Call SomeOtherSpecificSubRoutine
    End If

    Application.EnableEvents=True

End Sub
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top