Worksheet_Change事件使用实时数据源崩溃Excel

时间:2016-09-20 17:28:41

标签: excel vba excel-vba event-handling

我正在尝试运行由Private Sub Worksheet_Change(ByVal target As Range)事件驱动的代码。我希望我的代码能够实时分析数据,而不是每15-20分钟输入一大块数据来分析新数据。

我尝试运行的数据是通过API从数据服务输入的,并直播到我的Excel工作表中。我使用一个名为CMED.MA的函数,它有两个不同的参数(在当前时刻无关紧要)。它提供了向下滚动的行,因此您有一行,然后新数据将在下一行等中提供,等等。有时它相当快(每隔几秒)......其他时间它非常停滞(每隔几分钟左右)。 注意:数据一次只能以单行提供。

我创建了一堆函数并将它们存储在一个单独的模块中(所有Public Functions),以保持工作表模块的清洁和简短。

问题

在写了一小部分内容以涵盖实时数据的分析后,我想测试它(谢天谢地决定测试它),现在当我试图让代码在工作表模块中生效时,它完全崩溃了。我必须关闭源数据源,以便我可以禁用工作表模块中的代码。我的代码有任何想法或明显的问题吗?这是我第一次尝试使用Worksheet_Change事件

工作表模块代码

Option Explicit

Private Sub Worksheet_Change(ByVal target As Range)

    Dim initialTradeStructure As String, finalTradeStructure As String, rawStructure As String

    'RFQs
    If target.Item(1, 3) = "RequestForQuote" Then

        'Do Nothing....no analysis of RFQs is necessary....will be filtered later

    'Screen Trades
    ElseIf target.Item(1, 3) = "GlobexTrades" Then

        rawStructure = target.Item(1, 2)

        initialTradeStructure = Right(rawStructure, Len(rawStructure) - 4)

        'Bulk of analaysis conducted in analsyis engine to keep worksheet code clean/short
        finalTradeStructure = OptionStructureAnalysisEngine(initialTradeStructure, target)

    'Block screen represented as Multileg in datafeed structure
    ElseIf target.Item(1, 3) = "Block" Then

        If target.Item(1, 17) = "TRUE" Then

            rawStructure = target.Item(1, 2)

            initialTradeStructure = Right(rawStructure, Len(rawStructure) - 4)

            'Bulk of analysis conducted in analysis engine to keep worksheet code clean/short
            finalTradeStructure = OptionStructureAnalysisEngine(initialTradeStructure, target)

        ElseIf target.Item(1, 17) = "FALSE" And target.Item(1, 16) = "FALSE" Then

            'Live block trade

        Else

            'Do Nothing....No analysis of single block legs is necessary

        End If

    End If

    If Not finalTradeStructure = "Nothing" Then

        target.Item(1, 1) = finalTradeStructure

    End If

End Sub

功能模块

Public Function OptionStructureAnalysisEngine(tradeStructure As String, tradeDataRange As Range) As String
    'analyzes and translates tradeStructure and dataRange
    'Driver
    Dim structureAssemblyString As String, optionType As String

    'Tests for / in tradeStructure to determine if it's a LIVE option trade or if it's a multi leg structure
    If InStr(1, tradeStructure, "/") < 1 Then

        'Declares LIVE and option Type
        structureAssemblyString = "LIVE " & GetOptionCodes(Mid(tradeStructure, 8, 2)) & " " & TranslateExpirationDate(Mid(tradeStructure, 11, 6)) _
        & " " & GetCallOrPut(Mid(tradeStructure, 18, 1))

    Else

        'Place holder for multileg structures
        structureAssemblyString = "Nothing"

    End If

    OptionStructureAnalysisEngine = structureAssemblyString

End Function

Public Function GetOptionCodes(optionType As String) As String

    Select Case optionType

        Case "LO"

            GetOptionCodes = "WTI American"

        Case "OH"

            GetOptionCodes = "HO American"

        Case "OB"

            GetOptionCodes = "RB American"

        Case "LN"

            GetOptionCodes = "NG European"

    End Select

End Function

Public Function TranslateExpirationDate(expirationDate As Double) As String

    Select Case Right(expirationDate, 2)

        Case 1

            TranslateExpirationDate = "F" & Mid(expirationDate, 3, 2)

        Case 2

            TranslateExpirationDate = "G" & Mid(expirationDate, 3, 2)

        Case 3

            TranslateExpirationDate = "H" & Mid(expirationDate, 3, 2)

        Case 4

            TranslateExpirationDate = "J" & Mid(expirationDate, 3, 2)

        Case 5

            TranslateExpirationDate = "K" & Mid(expirationDate, 3, 2)

        Case 6

            TranslateExpirationDate = "M" & Mid(expirationDate, 3, 2)

        Case 7

            TranslateExpirationDate = "N" & Mid(expirationDate, 3, 2)

        Case 8

            TranslateExpirationDate = "Q" & Mid(expirationDate, 3, 2)

        Case 9

            TranslateExpirationDate = "U" & Mid(expirationDate, 3, 2)

        Case 10

            TranslateExpirationDate = "V" & Mid(expirationDate, 3, 2)

        Case 11

            TranslateExpirationDate = "X" & Mid(expirationDate, 3, 2)

        Case 12

            TranslateExpirationDate = "Z" & Mid(expirationDate, 3, 2)

    End Select

End Function

Public Function GetCallOrPut(legOption As String) As String
    'Translates C to Call and P to Put in option Structure

    If legOption = "C" Then

        GetCallOrPut = "Call"

    ElseIf legOption = "P" Then

        GetCallOrPut = "Put"

    End If

End Function

2 个答案:

答案 0 :(得分:1)

我看不到你的数据,也看不到这些子和函数如何与它们相互作用,但这是我对你的问题的盲目重写。我还重写了你的一个函数,使它更具可读性(对我而言)。

Sheet1 - 代码表

Option Explicit

Private Sub Worksheet_Change(ByVal Target As Range)
    If Target.Rows(1).Cells.Count = 18 Then
        'set a custom error procedure; essentially revert to as normal as ppossible
        On Error GoTo bm_Safe_Exit
        'turn off event handling so if anything is changed, the sub procedure does not try to walk on top of itself
        Application.EnableEvents = False
        'only dim things now that you know that something is actually going to happen
        Dim iTS As String, fTS As String, rS As String
        'always determine text comparisons as case-insensitive
        Select Case LCase(Target.Cells(1, 3).Value2)
            caae "requestforquote"
                'do nothing
            caae "globextrades"
                rS = Target.Cells(1, 2).Value2
                initialTritsadeStructure = Right(rS, Len(rS) - 4)
                'Bulk of analaysis conducted in analsyis engine to keep worksheet code clean/short
                fTS = OptionStructureAnalysisEngine(iTS, Target)
                'Block screen represented as Multileg in datafeed structure
            caae "block"
                'Is this actually TRUE/FALSE or text...????!!!?????
                Select Case UCase(Target.Item(1, 17).Text)
                    Case "TRUE"
                        rS = Target.Item(1, 2).Value2
                        iTS = Right(rS, Len(rS) - 4)
                    Case "FALSE"
                        'Bulk of analysis conducted in analysis engine to keep worksheet code clean/short
                        fTS = OptionStructureAnalysisEngine(iTS, Target.Cells(1, 1)) '<~~ need to know which of a typical target's 18 cells to throw into this
                    Case Else
                        'do nothing
                End Select
            Case Else
                'do nothing
        End Select
    End If

    If Not fTS = "Nothing" And CBool(Len(fTS)) Then
        Target.Item(1, 1) = fTS
    End If

bm_Safe_Exit:
    Application.EnableEvents = True
End Sub

Module1代码表

Option Explicit

Public Function OptionStructureAnalysisEngine(tradeStructure As String, tradeDataRange As Range) As String
    'analyzes and translates tradeStructure and dataRange
    'Driver
    Dim structureAssemblyString As String, optionType As String

    'Tests for / in tradeStructure to determine if it's a LIVE option trade or if it's a multi leg structure
    If InStr(1, tradeStructure, "/") < 1 Then
        'Declares LIVE and option Type
        structureAssemblyString = "LIVE " & GetOptionCodes(Mid(tradeStructure, 8, 2)) & " " & TranslateExpirationDate(Mid(tradeStructure, 11, 6)) _
                                    & " " & GetCallOrPut(Mid(tradeStructure, 18, 1))
    Else
        'Place holder for multileg structures
        structureAssemblyString = "Nothing"
    End If

    OptionStructureAnalysisEngine = structureAssemblyString

End Function

Public Function GetOptionCodes(optionType As String) As String

    Select Case UCase(optionType)
        Case "LO"
            GetOptionCodes = "WTI American"
        Case "OH"
            GetOptionCodes = "HO American"
        Case "OB"
            GetOptionCodes = "RB American"
        Case "LN"
            GetOptionCodes = "NG European"
        Case Else
            'do nothing
    End Select

End Function

Public Function TranslateExpirationDate(expirationDate As Long) As String
    Dim c As Integer, str As String
    c = CInt(Right(expirationDate, 2))
    str = Mid(expirationDate, 3, 2)
    Select Case c
        Case 1, 2, 3
            TranslateExpirationDate = Chr(c + 69) & str
        Case 4, 5
            TranslateExpirationDate = Chr(c + 70) & str
        Case 6, 7
            TranslateExpirationDate = Chr(c + 71) & str
        Case 8
            TranslateExpirationDate = Chr(c + 72) & str
        Case 9, 10
            TranslateExpirationDate = Chr(c + 76) & str
        Case 11
            TranslateExpirationDate = Chr(c + 77) & str
        Case 12
            TranslateExpirationDate = Chr(c + 78) & str
        Case Else
            'do nothing
    End Select
End Function

Public Function GetCallOrPut(legOption As String) As String
    Select Case UCase(legOption)
        Case "C"
            GetCallOrPut = "Call"
        Case "P"
            GetCallOrPut = "Put"
        Case Else
            'do nothing
    End Select
End Function

如前所述,我是盲目的。如果您无法使用或根据自己的目的进行修改,请修改原始问题以包含Minimal, Complete, and Verifiable example(根据需要编辑示例数据)。

答案 1 :(得分:0)

该行说

target.Item(1, 1) = finalTradeStructure

可能会导致无限循环,因为如果它被执行,它将触发一个新的Change事件。

我建议您只看一个列(不是您可能修改的列),例如:

Option Explicit

Private Sub Worksheet_Change(ByVal target As Range)

    Dim initialTradeStructure As String, finalTradeStructure As String, rawStructure As String

    'See if the change affects something in column 3 and only process if it does
    If Not Intersect(Target, Columns(3)) Is Nothing Then

        With Target.Rows(1)
            'RFQs
            If .Cells(1, "D") = "RequestForQuote" Then

                'Do Nothing....no analysis of RFQs is necessary....will be filtered later

            'Screen Trades
            ElseIf .Cells(1, "D") = "GlobexTrades" Then

                rawStructure = .Cells(1, "C")

                initialTradeStructure = Right(rawStructure, Len(rawStructure) - 4)

                'Bulk of analaysis conducted in analsyis engine to keep worksheet code clean/short
                finalTradeStructure = OptionStructureAnalysisEngine(initialTradeStructure, target)

            'Block screen represented as Multileg in datafeed structure
            ElseIf .Cells(1, "D") = "Block" Then

                If .Cells(1, "R") = "TRUE" Then

                    rawStructure = .Cells(1, "C")

                    initialTradeStructure = Right(rawStructure, Len(rawStructure) - 4)

                    'Bulk of analysis conducted in analysis engine to keep worksheet code clean/short
                    finalTradeStructure = OptionStructureAnalysisEngine(initialTradeStructure, target)

                ElseIf .Cells(1, "R") = "FALSE" And .Cells(1, "Q") = "FALSE" Then

                    'Live block trade

                Else

                    'Do Nothing....No analysis of single block legs is necessary

                End If

            End If

            If Not finalTradeStructure = "Nothing" Then

                .Cells(1, "B") = finalTradeStructure

            End If

        End With

    End If

End Sub

注意:我已将您的Target.Items(1,x)格式更改为Target.Rows(1).Cells(1,x+1)格式(将x + 1编码为实际的字母列名称),因为我认为这样可以更轻松地查看哪些列被提及。