检测嵌套公式的变化

我有一个非常复杂的工作簿与许多选项卡。 选项卡可能具有正常数据或各种单元格中的公式。 在公式的情况下,公式可以从一张纸嵌套到另一张(即,sheet1上的公式指的是sheet2上的公式,后者又指sheet3上的公式等)。

我有一个隐藏的选项卡,其中包含以下内容:源表单,源范围,目标表单和目标范围。

已经在这四个字段和所有适用的行上创build了一个已命名的范围。

当我们希望将数据保存到数据库时,我们遍历范围映射中的每一行,并将数据从源表单/范围复制到目标表单/范围。 之后,将适用的数据序列化为XML并发送到Web服务进行保存。

我们希望解决的问题是,当用户对源范围进行更改时,我们希望在隐藏工作表上标记单元格。 由于公式可以嵌套,Worksheet_Change事件不会接受更改。

由于在一个工作表上的更改可能会影响不是活动工作表的另一个工作表,Workbook_SheetChange事件也不捕获更改。

当映射中定义的图表发生更改时,是否有任何方法可以捕捉到,即使这是公式更改几个级别的结果?

编辑

谢谢你的回复。 我试图find最快和最less的过程密集型方式来确定数据是否在监控范围内变化。 数据可能由实际数据或嵌套公式组成。

我的研究表明,我不能通过采用范围交叉来实现这个结果,因为我无法检测到监控范围内的数据是否被修改。 这是由于监控的范围可能不在活动页面上,也可能包含公式。

我已经展示了用于实际检测下面的变化的方法。 如果有更好的方法有任何反馈,以达到相同的结果,我将不胜感激。

如果单元格值由公式更改,Worksheet_Change事件将不起作用,您需要Worksheet_Calculate。

看看我的示例工作簿在这里 。

在这里为例子代码的网页

当被监控的公式不在活动工作表上时,没有“简单”的方法来检测嵌套公式是否已经改变。 虽然我的希望是检测修改的范围并使用范围的交集来设置标志,但这是不可能的,因为Worksheet_Change事件不适用于公式,而Workbook_SheetChange事件仅适用于活动工作表。 由于我的工作簿有20多个标签和20-30个范围被监控,所以这种方法是行不通的。 这种方法对于速度的目的是期望的。

相反,工作簿将需要“检查”以查看当前值是否与上次调用保存到数据库事件时相同。 如果不是,将会设置一个脏标志。

下面提供了这种方法的代码。

映射范围的一个例子如下图所示,但实际上有20-30行包含这个范围。

映射范围

还有另外三张Sheet3包含A1中的实际数据:H1和Sheet2的公式指向Sheet3。 Sheet1有公式指向Sheet2。

如映射范围所示,我们正在查看Sheet1上的范围,即使可能会对Sheet3进行更改。

使用的代码如下所示。

Option Explicit Public Sub DetermineIfEditOccurred() Dim oMappingRange As Range Dim szSourceTab As String Dim szSourceRange As String Dim oSourceRange As Range Dim szTargetTab As String Dim szTargetRange As String Dim oTargetRange As Range Dim oWorksheetSource As Worksheet Dim oWorksheetTarget As Worksheet Dim oRangeIntersection As Range Dim nRowCounter As Long Dim nCellCounter As Long Dim szSourceValue As String Dim szTargetValue As String Dim oCell As Range Dim bIsDirty As Boolean If Range(ThisWorkbook.Names("DirtyFlag")).Value = 0 Then Set oMappingRange = Range(ThisWorkbook.Names("Mapping")) For nRowCounter = 1 To oMappingRange.Rows.Count szSourceTab = oMappingRange(nRowCounter, 1) szSourceRange = oMappingRange(nRowCounter, 2) szTargetTab = oMappingRange(nRowCounter, 3) szTargetRange = oMappingRange(nRowCounter, 4) Set oWorksheetSource = ThisWorkbook.Worksheets(szSourceTab) Set oWorksheetTarget = ThisWorkbook.Worksheets(szTargetTab) Set oSourceRange = oWorksheetSource.Range(szSourceRange) Set oTargetRange = oWorksheetTarget.Range(szTargetRange) nCellCounter = 1 For Each oCell In oSourceRange.Cells szSourceValue = oCell.Value If szSourceValue = "#NULL!" Or _ szSourceValue = "#DIV/0!" Or _ szSourceValue = "#VALUE!" Or _ szSourceValue = "#REF!" Or _ szSourceValue = "#NAME?" Or _ szSourceValue = "#NUM!" Or _ szSourceValue = "#N/A" Then szSourceValue = "" End If szTargetValue = GetCellValueByPosition(oTargetRange, nCellCounter) If szSourceValue <> szTargetValue Then Range(ThisWorkbook.Names("DirtyFlag")).Value = 1 bIsDirty = True Exit For End If nCellCounter = nCellCounter + 1 Next If bIsDirty Then Exit For End If Next End If End Sub Public Function GetCellValueByPosition(oRange As Range, nPosition As Long) As String Dim oCell As Range Dim nCounter As Long Dim szValue As String nCounter = 1 For Each oCell In oRange If nCounter = nPosition Then szValue = oCell.Value Exit For End If nCounter = nCounter + 1 Next GetCellValueByPosition = szValue End Function 

Workbook_SheetChange事件如下所示:

 Option Explicit Private Sub Workbook_BeforeClose(Cancel As Boolean) Call DetermineIfEditOccurred End Sub Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range) If Sh.Name <> "MAPPING" Then Call DetermineIfEditOccurred End If End Sub