События приложения, определяют, когда Excel действительно готов к чтению из - PullRequest
0 голосов
/ 20 марта 2020

Я пытался разрешить приложению связываться с Excel, используя COM-взаимодействие или Excel-днк. В идеале пользователи могут связывать ЛЮБУЮ рабочую книгу Excel, которая может содержать или не содержать код VBA. Обычно операция будет

i) C# запись в лист Excel

ii) Excel пересчитывает

iii) При желании Excel может запустить VBA, если какой-либо Worksheet_Change или Worksheet_Calculate события включаются пользователем

iv) C# и затем считываются из листа Excel, который будет содержать обновленные данные из calcs / VBA

Существует ли событие FINAL Application, которое уведомляет о завершении всего?

Например, события уровня приложения включают в себя AfterCalculate() и SheetChange, но один или оба могут сработать, что затрудняет определение того, на что реагировать, для iv) выше.

I ' мы настроили небольшой макетный проект в VBA, при изменении рабочего листа события уровня приложения инициируют в следующем порядке

Worksheet_Calculate
mApp_AfterCalculate Calc ended at: 20/03/2020 13:23:29
Worksheet_Change Started
Worksheet_Change Ended
mApp_SheetChange Calc ended at: 20/03/2020 13:23:29 --> New Value: 20/03/2020 13:23:29

Если есть простой способ узнать, будет ли конечное событие mApp_AfterCalculate или mApp_SheetChange?

Код проекта макета:

Лист 1:

Private Sub Worksheet_Calculate()
    Debug.Print ("Worksheet_Calculate")
End Sub

Private Sub Worksheet_Change(ByVal Target As Range)

    Debug.Print ("Worksheet_Change Started")
    Call Setup

    Application.EnableEvents = False
    Sheet1.Range("F1").Value = Now
    Application.EnableEvents = True

    Debug.Print ("Worksheet_Change Ended")
End Sub

Модуль класса: clsAppEvents

Option Explicit

Private WithEvents mApp As Application

Private Sub Class_Initialize()
    Set mApp = Application
End Sub

Private Sub mApp_AfterCalculate()
    Debug.Print "mApp_AfterCalculate Calc ended at: " & Now
End Sub

Private Sub mApp_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    Debug.Print "mApp_SheetChange Calc ended at: " & Now & " --> New Value: " & Sh.Range("F1").Value

End Sub

Module1:

Private mAppEvents As clsAppEvents

Public Sub Setup()
    If mAppEvents Is Nothing Then
        Debug.Print ("Setup initialized")
        Set mAppEvents = New clsAppEvents
    End If
End Sub

1 Ответ

2 голосов
/ 21 марта 2020

Исходя из того, что я понял по вашему вопросу, основная проблема заключается в том, что вы пытаетесь предсказать график вычислений Excel, предполагая, что события будут выполняться в определенном порядке, и что они всегда будут выполняться синхронно ... Оба из которых вы не можете надежно предсказать 100% времени.

Я бы предложил использовать другой, более надежный подход, когда вы отделяете запись от чтения:

  • Запись : Для кода C#, который пишет в электронную таблицу, сделайте именно это. Пишите и ничего не ждите (и ничего не читайте)

  • Чтение : Также на стороне C# подпишитесь на Application.SheetChange и реагировать там - т. е. каждый раз, когда это событие запускается на стороне C#, считывайте нужные значения из электронной таблицы.

Таким образом, не имеет значения, кто изменил электронную таблицу. .. Если это был ваш код C#, код VBA или пользователь, изменивший его вручную. Вы знаете, что каждый раз, когда в электронной таблице происходит изменение, ваш код C# запускается и дает вам возможность реагировать (или нет) в зависимости от того, произошло ли изменение в списке, который вам небезразличен, а также что изменение произошло в диапазон, который вас волнует.

Псевдокод, как будет выглядеть ваш Application.SheetChange:

public void Application_SheetChange(object sheet, Range range) 
{ 
    if (range.Worksheet.Name != "SheetYouAreInterested")
    {
        return; // nothing to do
    }

    if (!range.IntersectsWith(rangeYouAreInterested))
    {
        return; // nothing to do
    }

    // Read the values that changed, etc.
}

Теперь порядок событий также не важен, учитывая, что ваш обработчик событий будет выполняться каждый раз, когда происходит изменение, поэтому любые устаревшие значения, которые вы, возможно, прочитали раньше, будут в конечном итоге обновлены к моменту последнего запуска события.

Конечно, код чтения не должен вносить какие-либо изменения в непосредственно лист ... Он должен только читать, иначе вы застряли бы в бесконечном l oop: D

...