作为可选参数的范围应默认为调用单元格的完整工作表。如何?

时间:2019-09-03 10:43:19

标签: excel vba

我写了一个UDF,它把范围作为可选参数。然后,它计算所使用范围的最后一行。如果未将范围作为参数传递,则UDF应该默认为调用单元格的完整工作表。不知何故,直截了当的方法不起作用-UDF返回0。

var inputString = $('body').html();
inputString = inputString.replace(/(\r\n|\r|\n){2,}/g, '$1\n');
$('body').html(inputString);

正如我所说,如果我在单元格“ = hrLastRow()”中调用此方法,尽管到处都有值,但结果为零:)-因此结果肯定是肯定的。

也许我没有正确使用Application.Caller ...?任何帮助将非常感激。还是VBA不允许以某种方式进行递归调用?那为什么是零?

PS:在射程上工作正常。

PPS:我刚刚注意到,Excel警告调用单元格中有循环引用。也许这是潜在的问题-但是,如何解决呢?


更新: 因此,目标是要使该工作无副作用,例如迭代计算。有人建议只是在UDF调用者下面进行搜索以避免循环引用,这对我来说似乎是一个聪明的主意,既简单又针对性。不知何故,我的代码似乎很笨拙,但是结果刚刚关闭...这是UDF的当前状态。只要看一下r是否无关紧要:

var inputString = document.getElementsByTagName('body')[0].innerHTML;
inputString = inputString.replace(/(\r\n|\r|\n){2,}/g, '$1\n');
document.getElementsByTagName('body')[0].innerHTML.html(inputString);

外部if语句的else部分工作正常。

2 个答案:

答案 0 :(得分:0)

感谢所有贡献者。

特别感谢BrakNicku提出的简单但聪明的想法,即仅在调用单元格下方进行搜索以避免循环引用。

随时使用以下代码。 这是最终功能,可以按需工作:

Public Function hrLastRow(Optional r As Range = Nothing) As Long
    Application.Volatile True
    If r Is Nothing Then
        Dim callerRow   As Long
        Dim callerWS    As Worksheet
        Dim searchRange As Range
        Set callerWS = Application.Caller.Parent
        callerRow = Range(Application.Caller.Address).row
        With callerWS
            Set searchRange = .Range(.Cells(callerRow + 1, 1), .Cells(callerRow + .UsedRange.Rows.Count, .UsedRange.Columns.Count))
            If Application.WorksheetFunction.CountA(searchRange) <> 0 Then
                hrLastRow = searchRange.Find(What:="*", _
                                After:=searchRange.Cells(1, 1), _
                                LookAt:=xlPart, _
                                LookIn:=xlFormulas, _
                                SearchOrder:=xlByRows, _
                                SearchDirection:=xlPrevious, _
                                MatchCase:=False).row
            Else
                hrLastRow = callerRow
            End If
        End With
    Else
        If Application.WorksheetFunction.CountA(r) <> 0 Then
            hrLastRow = 1 - r.Rows(1).row + _
                        r.Find(What:="*", _
                            After:=r.Cells(1, 1), _
                            LookAt:=xlPart, _
                            LookIn:=xlFormulas, _
                            SearchOrder:=xlByRows, _
                            SearchDirection:=xlPrevious, _
                            MatchCase:=False).row
            hrLastRow = Application.WorksheetFunction.Max(hrLastRow, 0)
        Else
            hrLastRow = 0
        End If
    End If
End Function

答案 1 :(得分:-1)

在您的工作簿模块上写入:

Option Explicit
Private Sub Workbook_Activate()
    With Application
        .Iteration = True
        .MaxIterations = 1000
        .MaxChange = 0.001
    End With
End Sub
Private Sub Workbook_Deactivate()

    Application.Iteration = False

End Sub

并将其添加到您的函数中:

Option Explicit
Public Function hrLastRow(Optional r As Range = Nothing) As Long

    If Application.Iteration = False Then End
    If r Is Nothing Then
        hrLastRow = hrLastRow(ThisWorkbook.Worksheets(Application.Caller.Parent.Name).Cells())
    Else
        If Application.WorksheetFunction.CountA(r) <> 0 Then
            hrLastRow = 1 - r.Rows(1).Row + _
                        r.Find(What:="*", _
                            After:=r.Cells(1, 1), _
                            LookAt:=xlPart, _
                            LookIn:=xlFormulas, _
                            SearchOrder:=xlByRows, _
                            SearchDirection:=xlPrevious, _
                            MatchCase:=False).Row
            hrLastRow = Application.WorksheetFunction.Max(hrLastRow, 0)
        Else
            hrLastRow = 0
        End If
    End If

End Function

这样,迭代计算将仅在此工作簿上被激活,如果未激活,则不会重新计算您的函数。