【问题标题】:Get the address of a dynamic range from a validation formula从验证公式中获取动态范围的地址
【发布时间】:2012-11-15 01:45:49
【问题描述】:

我的代码使用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

此测试应使用单元格A1A2 的内容将下拉验证分配给单元格B1,然后检查B1 的内容是否与其中任何一个单元格匹配。但它在Set ResultRange 行失败并出现此错误:

Method 'Range' of object '_Global' failed.

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

那么,给定我将动态参数传递给的这个OFFSET() 公式,我如何获得这个公式为rng 指定的范围返回的范围?

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

【问题讨论】:

  • 那么...在您假设的工作情况下,偏移公式是通过代码计算还是硬编码为字符串?
  • @DanielCook,偏移公式被硬编码为命名范围。
  • 我只是想清楚地理解......所以你是说在实际用例中你的公式不是"=OFFSET(INDIRECT(ADDRESS(ROW(),COLUMN())),0,-1,2,1)"之类的东西,而是"=NamedRange"之类的东西?我特别想澄清的是,如果您期待 =OFFSET(A1,2,3,B1,B2) 之类的内容,或者这些数字是否会被硬编码。
  • @DanielCook:列和行偏移量将被硬编码,就像您刚刚给出的 OFFSET(INDIRECT(...)) 示例一样。同样,应用程序中有几个不同的 OFFSET() 公式,因此最实用的解决方案是返回为该单元格和公式计算的范围的函数 ReturnRange(initialRange as Range,offsetFormula as String)。
  • 我就是这么想的。我同意你的看法,我只是想在为你写之前澄清一下。但是......既然你澄清了我将你的函数头 sn-p 扩展为一个函数。

标签: validation vba excel


【解决方案1】:

这不是很漂亮,但会做你喜欢的事情你必须已经定义了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

【讨论】:

  • 谢谢,但这需要我在更改OFFSET() 公式时更改这行代码。我需要一些没有硬编码的东西;我会相应地修改我的问题。
猜你喜欢
  • 2014-12-21
  • 1970-01-01
  • 2017-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多