应用程序事件,确定Excel何时真正可以读取
我一直在考虑允许应用程序使用COM互操作或Excel dna与Excel链接。理想情况下,用户可以链接任何可能包含或不包含VBA代码的Excel工作簿。通常情况下,操作是 i) C#写入Excel工作表 ii)Excel重新计算 iii)如果用户包含任何工作表更改或工作表计算事件,Excel也可以运行VBA iv)C#然后从Excel表格中读取,该表格将包含来自calcs/VBA的更新数据 是否有最后一个应用程序事件在所有操作完成时发出通知 例如,应用程序级事件包括应用程序事件,确定Excel何时真正可以读取,excel,vba,com-interop,excel-dna,Excel,Vba,Com Interop,Excel Dna,我一直在考虑允许应用程序使用COM互操作或Excel dna与Excel链接。理想情况下,用户可以链接任何可能包含或不包含VBA代码的Excel工作簿。通常情况下,操作是 i) C#写入Excel工作表 ii)Excel重新计算 iii)如果用户包含任何工作表更改或工作表计算事件,Excel也可以运行VBA iv)C#然后从Excel表格中读取,该表格将包含来自calcs/VBA的更新数据 是否有最后一个应用程序事件在所有操作完成时发出通知 例如,应用程序级事件包括AfterCalculate(
AfterCalculate()
和SheetChange
,但其中一个或两个可能会触发,这使得很难知道对上面iv)中的哪一个做出反应
我在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
Private mAppEvents As clsAppEvents
Public Sub Setup()
If mAppEvents Is Nothing Then
Debug.Print ("Setup initialized")
Set mAppEvents = New clsAppEvents
End If
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
模块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
Private mAppEvents As clsAppEvents
Public Sub Setup()
If mAppEvents Is Nothing Then
Debug.Print ("Setup initialized")
Set mAppEvents = New clsAppEvents
End If
End Sub
从我对你的问题的理解来看,基本问题是,你试图通过假设事件将按特定顺序执行来预测Excel的计算图,并且它们将始终同步执行。。。这两种情况你都无法100%可靠地预测 我的建议是使用一种不同的、更可靠的方法,将写作与阅读分离开来:
- 写入:在写入电子表格的C#代码上,只需这样做。写作,不要等待任何东西(也不要阅读任何东西)
- 读取:同样在C端,订阅
并在那里做出反应-即每次在C端运行此事件时,从电子表格中读取所需的值应用程序。SheetChange
应用程序.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.
}
现在,事件的顺序也不再重要了,因为您的事件处理程序将在每次发生更改时不断执行,因此您以前可能读取的任何陈旧值最终将在事件上次运行时刷新
当然,阅读代码不应直接对工作表进行任何更改。。。它应该是这样写的,否则你会陷入一个无限循环中:从我对你的问题的理解来看,根本问题是,你试图通过假设事件将按一定顺序执行来预测Excel的计算图,并且它们总是同步执行。。。这两种情况你都无法100%可靠地预测 我的建议是使用一种不同的、更可靠的方法,将写作与阅读分离开来:
- 写入:在写入电子表格的C#代码上,只需这样做。写作,不要等待任何东西(也不要阅读任何东西)
- 读取:同样在C端,订阅
并在那里做出反应-即每次在C端运行此事件时,从电子表格中读取所需的值应用程序。SheetChange
应用程序.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.
}
现在,事件的顺序也不再重要了,因为您的事件处理程序将在每次发生更改时不断执行,因此您以前可能读取的任何陈旧值最终将在事件上次运行时刷新
当然,阅读代码不应直接对工作表进行任何更改。。。它应该只读,否则你会陷入一个无限循环:d