Excel:范围内的先前值

Excel: Previous Values from Ranges

我想在复制单个单元格并将其粘贴到多个单元格时获取以前的单元格值。 How can I determine new & previous cell value on SheetChange event in Excel? 足以检测单个单元格的先前值。但是,当我尝试复制一个单元格(ctrl+v、拖动等)并将其应用于多个单元格时,检测到先前值的 none。相反,值数组等于第一个单元格,这使我得出结论,单元格在 SheetSelectionChange 事件发生之前发生了更改。知道如何处理吗?

private void Application_SheetSelectionChange(object Sh, Excel.Range Target)
    {
        try
        {
            if (Target.Value2 != null)
            {
                foreach (Excel.Range range in Target)
                {
                   // Each range in Target has same value as first value instead of previous value
                }
            }
        }
        catch (Exception ex)
        {
           // Log stuff
        }
    }

恐怕要实现监控所有 sheet 个细胞的目标,您必须:

  • 制作一个 "mirror" 整个副本 "base" sheet

    其中的每个单元格将引用 "base" sheet 中的相应单元格(即 "mirror" sheet A1 单元格将具有“="baseSheetName!A1"公式”,等等)

  • 在 "base" sheet 中进行任何更改之前设置 Application.Calculation = xlCalculationManual(可能在工作簿打开时将其设置为默认配置)

  • 使用 Worksheet_SelectionChange() 事件处理程序的 Target 参数到 select 相应的 "Mirror" sheet 单元格,感谢 Application.Calculation = xlCalculationManual 设置,将仍然有以前的值

如果您担心 "base" sheet 个单元格的数量有限,您可以以类似的方式继续,但将 "mirror" 个单元格保留在 "base" sheet本身

在后一种情况下,这里有一个代码来处理它(注意:VBA 代码,但您可以轻松地用 C# 翻译”)

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim sensitiveRange As Range
Dim sensitiveRangeSelected As Range

Set sensitiveRange = Range("sensitiveRange")
Set sensitiveRangeSelected = Application.Intersect(sensitiveRange, Target)
If sensitiveRangeSelected Is Nothing Then
    ' no 'sensitive' cells  --> go ahead
Else
    ' 'sensitive' cells !! -> add code to handle thier value or store it in some array
End If

End Sub

你必须在你的 "base" sheet 中设置一个命名范围(我称之为 "sensitiveRange"),其中的所有单元格都必须被跟踪

您可以在 运行 Undo 之前获取选择,并在过程结束时恢复它。

注意:如果 sheet 未激活(例如,在 sheet 被代码更新的情况下),最后的 Select 将失败,因此您可能需要检查一下。

Private Sub Worksheet_Change(ByVal Target As Range)

    Dim Where As String, OldValue As Variant, NewValue As Variant
    Dim r As Long, c As Long, tmp
    Dim sel As Object '<<< current selection: not always a Range!
    Dim rngTrack As Range

    On Error GoTo haveError
    Application.EnableEvents = False
    Set sel = Selection '<<< capture the selection
    Where = Target.Address
    NewValue = Target.Value
    Application.Undo
    OldValue = Target.Value 'get the previous values
    Target.Value = NewValue
    Application.EnableEvents = True

    Set rngTrack = Sheets("Tracking").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)

    'set some limit for the size of change you want to track
    If Target.Cells.CountLarge < 1000 Then

        'convert single-cell values to array...
        If Target.Cells.CountLarge = 1 Then
            OldValue = ToArray(OldValue)
            NewValue = ToArray(NewValue)
        End If

        'multi-cell: treat as arrays
        For r = 1 To UBound(OldValue, 1)
        For c = 1 To UBound(OldValue, 2)
            If OldValue(r, c) <> NewValue(r, c) Then
                rngTrack.Resize(1, 3).Value = _
                  Array(Target.Cells(r, c).Address, OldValue(r, c), NewValue(r, c))
                Set rngTrack = rngTrack.Offset(1, 0)
            End If
        Next c
        Next r
    End If

    sel.Select '<<< reset the selection
    Exit Sub

haveError:
    Application.EnableEvents = True

End Sub
'utility function
Private Function ToArray(v)
    Dim rv(1 To 1, 1 To 1)
    rv(1, 1) = v
    ToArray = rv
End Function