从验证公式获取动态范围的地址

时间:2012-11-10 01:23:03

标签: validation vba excel-vba excel

我的代码使用OFFSET公式给出的范围设置单元格上的列表验证,该公式取决于该单元格的地址。

因为这个验证是在已经有内容的单元格上以编程方式设置的,所以我想要一个函数来确定该单元格的现有内容是否违反了验证。

我使用以下代码测试了这个问题:

Sub test()
    Dim sht As Worksheet
    Dim rng As Range
    Dim formula As String
    Dim rangeName As String
    Set sht = ThisWorkbook.Sheets("Sheet1")
    With sht
        .Range("a1").Value = "a"
        .Range("a2").Value = "aa"
        Set rng = .Range("b1")
        formula = "=OFFSET(INDIRECT(ADDRESS(ROW(),COLUMN())),0,-1,2,1)"
        rng.Validation.Add Type:=xlValidateList, Formula1:=formula
        rangeName = Replace(formula, "=", "")
        Set ResultRange = .Range(rangeName).Find(rng.Value, lookat:=xlWhole)
        If ResultRange Is Nothing Then
            Debug.Print "violates validation"
        Else
            Debug.Print "validated"
        End If
    End With
End Sub

此测试应使用单元格B1A1的内容为单元格A2分配下拉验证,然后检查B1的内容是否匹配那些细胞但它在Set ResultRange行失败并出现此错误:

Method 'Range' of object '_Global' failed.

我认为问题在于,当我调用Range(rangeName)时,Excel不知道将ROW()COLUMN()应用到哪个单元格,所以我需要以某种方式计算地址formula解析为此单元格 - 在本例中为$A$1:$A$2,以便我可以将该值分配给RangeName

因此,根据我传递动态参数的OFFSET()公式,如何获得此公式为rng指定的范围返回的范围?

编辑:由于公式可能会根据不同的情况而变化,我正在寻找一个解决方案,给定从某个范围开始的OFFSET()公式,返回该公式给出的范围。硬编码的解决方案是不可接受的,因为工作表中有几个不同的OFFSET()公式,每当其中一个公式发生变化时,更改验证测试的代码是不切实际的。

1 个答案:

答案 0 :(得分:0)

这不是很好,但会做你喜欢的,你必须已经定义rng,并且rng不能在A列中:

rangeName = .Range(.Cells(rng.Row, rng.Column - 1), .Cells(rng.Row + 1, rng.Column - 1)).Address

另外请注意,默认情况下,您的验证会忽略空白,因此您可能需要更新if以检查空白:

If ResultRange Is Nothing And rng.Value <> "" then
    Debug.Print "violates validation"
Else
    Debug.Print "validated"
End If

根据要求编辑,我继续并使OffsetFormula可选,因为它将假设传递的范围具有需要解析的公式:

Function ReturnRange(initialRange As Range, Optional OffsetFormula As String) As Range
    Dim parameters
    Dim upBound As Long
    Dim topLeftCell As Range
    Dim bottomRightCell As Range
    On Error Resume Next
    'If an error occurs result will be Nothing
    If OffsetFormula = "" Then OffsetFormula = initialRange.Formula
    If UCase(Left(OffsetFormula, 7)) = "=OFFSET" Then
        parameters = Split(Left(OffsetFormula, Len(OffsetFormula) - 1), ",")
        'Using upbound variable to avoid constant calls to Ubound(parameters)
        upBound = UBound(parameters)
        Set topLeftCell = initialRange.Offset(parameters(upBound - 3), parameters(upBound - 2))
        Set bottomRightCell = topLeftCell.Offset(parameters(upBound - 1) - 1, parameters(upBound) - 1)
        Set ReturnRange = Range(topLeftCell, bottomRightCell)
    End If
End Function