Run a macro when certain cells change in Excel but from my Personal workbook

前端 未结 1 1452
故里飘歌
故里飘歌 2021-01-16 08:31

Problem: I have found many postings (including Microsoft\'s own support site) containing information on how to run a macro when certain cells change in Exce

相关标签:
1条回答
  • 2021-01-16 08:57

    Since I faced the same problem, I worked my way through Chip Pearson's instructions and will provide you with a more comprehensive guide.

    I can also really encourage you to read your way through Chip Pearson's great summary on events. I know it's a lot to digest, but it will greatly help you understand what we actually do here.

    As an overview, these are the steps we are going to perform:

    1. Add a class module for our event handlers (This is where the actual event handling code will go)
    2. Add an event handler to our personal.xlsb's ThisWorkbook module to wire-up our event handler class
    3. Enjoy infinite event handling loops because we changed the Target.Value :-P (optional)

    Let's get started.

    1. Add a class module

    First, we need to create a cozy plaze to put all our event handlers. We will use a class module for this, since it provides some nice structure and you immediately know where to look for your application level event handlers.

    In your personal.xlsb's VBA project create a new class by right clicking in the project browser -> insert -> class module.

    Rename the class to CAppEventHandler by changing the name in the properties pane.

    Add the source code listed below (both the setup part and the event handling part) to the class you just created. (Make sure to read the comments, because they add some additional information to what we are doing and why.)

    2. Add the initializing event handler

    Now we need to make sure our event handlers are "activated" when our personal.xlsb is opened (so anytime you open Excel :)).

    To do this, double click your ThisWorkbook module and add the code below.

    Now you are actually already good to go and can test your event handling. The only thing you will have to do beforehand (in order to trigger the "wiring-up" process) is restart Excel.

    Notes

    • I added a check for the current sheet's name at the beginning of the event handler - so make sure your sheet is named "MySheet" :)
    • You can set a breakpoint inside the handler and watch it in action just like any other piece of VBA code

    And a word of warning (aka 3. Enjoy infinite event handling loops)
    When I tested this, I naively used Target.Value = "It wooooorks!" as the code to be executed if we changed the right cell on the right sheet. That was not good.
    See the last snippet of code (also taken from Chip's post) for how to prevent such an event loop.

    Source code

    In the CAppEventHandler class (setup)

    Option Explicit
    
    ' Declare our own reference to the Application object
    ' WithEvents is needed to capture the events of the application object
    ' (Note: The events 'bubble up' from the Worksheet to the Workbook and
    '        finally to the Application.
    '        So event handlers in the Sheet module are executed first
    '        (if any handlers are declared), then the ones in the Workbook
    '        module (again, if they are declared) and finally the ones
    '        in the Application module.)
    Private WithEvents App As Application
    
    ' Whenever a new object of a class is instantiated, the _Initialize-Sub is called,
    ' that's why we use this Sub to get the reference to the current Application object
    Private Sub Class_Initialize()
        Set App = Application
    End Sub
    

    In the CAppEventHandler class (actual event handling)

    ' Here is the actual code executed whenever the event reaches the Application level
    ' (see above for the order of 'bubbling up' of the events) and hasn't been marked
    ' as handled before
    Private Sub App_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    
        If Sh.Name <> "MySheet" Then
            Exit Sub
        End If
    
        Dim rngKeyCells As Range
        Set rngKeyCells = Sh.Range("A5")
    
        If Intersect(rngKeyCells, Target) Is Nothing Then
            Exit Sub
        End If
    
        ' Do our actual work
        MsgBox "It wooooorks!", vbInformation
    
        ' Note: If you want to change the contents of your keyCells, you will
        '       have to make sure to prevent an infinite event loop (i.e. using
        '       Application.EnableEvents = False because otherwise changing
        '       the value in your macro will trigger the event again
    
    End Sub
    

    In the ThisWorkbook module

    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ' The following code must be placed in the "ThisWorkbook" module of your personal.xlsb
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Option Explicit
    
    Private OurEventHandler As CAppEventHandler
    
    Private Sub Workbook_Open()
        ' Since we declared so in our _Initialize-Sub this wire-up the current
        ' Application object in our EventHandler class
        Set OurEventHandler = New CAppEventHandler
    End Sub
    

    How to prevent event loops

    Private Sub Worksheet_Change(ByVal Target As Range)
        Application.EnableEvents = False
        Target.Value = Target.Value + 1
        Application.EnableEvents = True
    End Sub
    

    (from Chip Pearson's comprehensive post on events)

    0 讨论(0)
提交回复
热议问题