How to ensure Excel calculation is completed from within a VBA procedure

前端 未结 2 555
渐次进展
渐次进展 2021-01-16 07:39

In an excel-spreadsheet user-defined functions are used to calculate basic results as spread-sheet matrices (cross-section values of composite elements).

Pu         


        
2条回答
  •  感情败类
    2021-01-16 07:59

    If the solution as explained in your answer is working for you then great. I'm just wondering if you're aware of the application's AfterCalculate event (https://msdn.microsoft.com/en-us/vba/excel-vba/articles/application-aftercalculate-event-excel):

    This event occurs whenever calculation is completed and there are no outstanding queries. It is mandatory for both conditions to be met before the event occurs. The event can be raised even when there is no sheet data in the workbook, such as whenever calculation finishes for the entire workbook and there are no queries running.

    Add-in developers use the AfterCalculate event to know when all the data in the workbook has been fully updated by any queries and/or calculations that may have been in progress.

    This event occurs after all Worksheet . Calculate , Chart . Calculate , AfterRefresh , and SheetChange events. It is the last event to occur after all refresh processing and all calc processing have completed, and it occurs after Application . CalculationState is set to xlDone .

    It might be an easier implementation for you. The trick to access the application object's events is to declare it WithEvents in a class module. For the example, I've called the class clsAppEvents:

    Option Explicit
    
    Private WithEvents mApp As Application
    
    Private Sub Class_Initialize()
        Set mApp = Application
    End Sub
    
    Private Sub mApp_AfterCalculate()
        Debug.Print "Calc ended at: " & Now
        ConsumeAfterCalculate
    End Sub
    

    In your module, you'd simply have the calling and event handling code:

    Option Explicit
    
    Private mAppEvents As clsAppEvents
    Private mEnableConsume As Boolean
    
    Public Sub RunMe()
        Set mAppEvents = New clsAppEvents
    End Sub
    Public Sub ConsumeAfterCalculate()
        If mEnableConsume Then
            Debug.Print "Sub called at: " & Now
            mEnableConsume = False
        End If
    End Sub
    Public Sub ConsumeButtonClick()
        Debug.Print "Button clicked at: " & Now
        mEnableConsume = True
    
        'For demo purposes I'm just forcing a calculation on existing data.
        Sheet1.EnableCalculation = False
        Sheet1.EnableCalculation = True
    End Sub
    

    FYI, the debug results were as follows:

    Button clicked at: 25/10/2017 4:49:20 p.m.

    Calc ended at: 25/10/2017 4:49:22 p.m.

    Sub called at: 25/10/2017 4:49:22 p.m.

提交回复
热议问题