Excel UDF将评估的SUB的值加倍

时间:2017-08-08 09:25:00

标签: excel excel-vba user-defined-functions vba

1。我试图回答VBA UDF to split string array并在计算我的UDF时遇到了令人不快的结果。

Public Function mytest(src, dest)
    dest.Parent.Evaluate "test(" & src.Address(False, False) & ", " & dest.Address(False, False) & ")"
    mytest = "wut"
End Function

Sub test(src As Range, dest As Range)
    Dim chr, rows, cols
    rows = 0
    cols = 0
    For chr = 1 To Len(src.Value)
        Select Case Mid(src.Value, chr, 1)
            Case ","
            rows = rows + 1
            Case ";"
            cols = cols + 1
            rows = 0
            Case Else
            Cells(dest.Row + rows, dest.Column + cols).Value = Cells(dest.Row + rows, dest.Column + cols).Value & Mid(src.Value, chr, 1) '
        End Select
    Next chr
End Sub

预期结果: enter image description here 公式结果: enter image description here 有人可以解释为什么它会加倍细胞的价值吗? 当我使用

调试测试
Sub ffs()
    Call test(Cells(1, 1), Cells(3, 1))
End Sub

我得到了预期的结果,所以我猜问题不在测试 Sub?..

2. 每当我尝试向Function和Sub添加更多参数时(例如分隔符)功能根本不评估Sub

Public Function CellToRange(src, dest, DelimL, DelimC)
    dest.Parent.Evaluate "test(" & src.Address(False, False) & ", " & dest.Address(False, False) & ", " & DelimL & ", " & DelimC & ")"
    CellToRange = "wut"
End Function

Sub CTR(src As Range, dest As Range, Delim1, Delim2)
    Dim chr, rows, cols
    rows = 0
    cols = 0
    For chr = 1 To Len(src.Value)
        Select Case Mid(src.Value, chr, 1)
            Case Delim1
            rows = rows + 1
            Case Delim2
            cols = cols + 1
            rows = 0
            Case Else
            Cells(dest.Row + rows, dest.Column + cols).Value = Cells(dest.Row + rows, dest.Column + cols).Value & Mid(src.Value, chr, 1) '
        End Select
    Next chr
End Sub

请帮助._。并提前感谢。
解决方案:
谢谢比利和查尔斯威廉姆斯 变化

dest.Parent.Evaluate "CTR(" & src.Address(False, False) & ", " & dest.Address(False, False) & ", " & DelimL & ", " & DelimC & ")"

dest.Parent.Evaluate "0+CTR(" & src.Address(False, False) & ", " & dest.Address(False, False) & ", " & DelimL & ", " & DelimC & ")"

谢谢大家!

2 个答案:

答案 0 :(得分:3)

问题在于Worksheet.Evaluate方法,该方法用于解决不允许UDF修改工作表结构的限制。

考虑这段代码

Option Explicit

Public Function dummyudf() As String
    Debug.Print "Calling Evaluate method"
    ActiveSheet.Evaluate "testsub()"
    Debug.Print "Returning From Evaluate method"
    dummyudf = "done"
End Function

Sub testsub()
    Debug.Print "testsub running"
End Sub

Sub testmacro()
    Dim s As String
    Debug.Print "testmacro running"
    s = dummyudf
End Sub

UDF dummyudf()使用Evaluate方法invoke Sub调用testsub()。这些与OP的第1部分中的mytesttest以及第2部分中的CellToRangeCTR类似,但都被剥离到最低限度。

testsub()也可以作为宏直接调用。第二个宏testmacro在VBA中调用dummyudf作为函数。

以下输出是从立即窗口获得的:

Output from Immediate Window

可以看出

  • 作为宏调用时:testsub()按预期行事

  • 在工作表上将dummyudf()作为UDF调用时(例如,通过将公式=dummyudf()添加到单元格A1Evaluate方法似乎会调用{ {1}}两次

  • 通过将testsub()作为宏运行,dummyudf()作为VBA中的函数调用testmacro()方法似乎两次调用Evaluate

文档here表明testsub()方法的 Name 参数应该是对象的名称,因此有点可以提供它Worksheet.Evaluate的名称。它似乎也两次调用任何此类Sub,更令人惊讶,但强调了YowE3K的答案中给出的关于不在UDF中使用此hack的建议。我要走得更远:不要Sub使用任何Worksheet.Evaluate

答案 1 :(得分:1)

1)它在触发公式时评估一次,并且当函数更新单元格A3时再次评估(因为它是公式所依赖的单元格之一)。

2a)你正在调用错误的子程序(test而不是CTR

2b)你需要使用像

这样的东西来调用你的第二个函数
=CellToRange(A1;A3;""",""";""";""")

或者更改代码中的行,将CTR命名为

dest.Parent.Evaluate "CTR(" & src.Address(False, False) & ", " & dest.Address(False, False) & ", """ & DelimL & """, """ & DelimC & """)"

3)我强烈建议你不要使用这种黑客来获取UDF来更新包含该函数的单元格以外的单元格。