如何有效地编码以访问VBA中的全局命名范围

时间:2019-01-04 19:10:29

标签: excel vba excel-vba named-ranges

我正在寻找在VBA中处理全局命名范围的替代通用编码方法。我希望在这里提供一些新的广义建议和方法的答案。

我建议使用一些方法,但是这些方法不能避免所有问题-我想要:易于编码和电子表格起草;电子表格更改的容忍度;以及几个月后即可轻松查找/参考。

在起草以后将使用VBA的电子表格时,我在电子表格公式中创建了命名范围(通常是全局名称)。范围在表格上有用,也可以作为VBA的参考。通常,我不会在VBA中添加/更改名称集合。我只引用集合。

编码VBA时,我访问在工作簿中创建的命名范围。如果我剪切/粘贴命名的单元格/范围,编辑工作簿和工作表,则VBA仍然有效。

但是,在工作表环境中创建的全局名称并不能满足VBA环境中的所有三个要求-尤其是在修改代码或修改工作表时。

在我的完美世界中:

wb.range("myGlobalRangeName")

“我的完美世界” 希望在电子表格上创建的工作簿的全局引用是全局的,但VBA希望对此引用在ActiveWorkBook和ActiveWorkSheet上。 / p>

思想之一::我知道Range("myGlobalRangeName")访问该范围,并且

因此,我经常使用此片段

wb.Worksheets("SheetOne").Range("myGlobalRangeName")

可以在With块内部构造,即使范围是全局引用,也可以指定工作表。

将已命名的单元格移动到其他工作表会中断此引用(即使名称为Global!)。我必须回溯所有代码以查找错误的引用。或者我可以执行代码,希望能发现错误...

思想二:我可以这样写,以访问工作簿的名称集合:

wb.Names("myGlobalRangeName").RefersToRange

但是必须附加RefersToRange是...。它错过了完美世界的简单性。

第三个思想::我创建了一个独特的worksheet,其中包含我想在其他工作表中捕获的所有值,并且仅在该不同工作表上创建了范围。工作簿中的单元格引用以及通过VBA访问的单元格引用均起作用。这样,VBA始于

Dim wsNames as spreadsheet
set wsNames = wb.worksheets("SheetWithNames")

和名称引用始终使用wb.wsNames,看起来像这样:

with wb
    .... .wsNames.range("myGlobalRangeName") ....
end with

或其他有用的变体形式。

但是,这也会变得很混乱-当我稍后修改电子表格或VBA时,我必须回溯以查看真实数据在哪里。有时候,这种方法行得通,特别是如果我只为供VBA使用而在该工作表上顽强地命名范围,使用真正令人难忘的名称并记住位置,并记得我在这几个月后做了所有的事情...

结论:我缺少什么吗?除了使用

以外,还有其他(也许更容易)的通用编码方法吗?
  • RefersToRangename collection
  • wb.worksheets("SheetName").Range("myGlobalRange")引用可明确标识[当前]工作表,或
  • 将RangeNames和引用公式放在另一张纸上,VBA范围引用为wsNames.Range("myGlobalRange")

我不想输入太多;或创建过程变量以在赋值中使用它们之前捕获值。如果我要在另一个工作簿中将一个单元格的值分配给另一个单元格,并且一个或两个都使用全局范围,那么混乱就变得...好难读,更难追踪。

2 个答案:

答案 0 :(得分:0)

通常,我可以通过Workbook Names集合获得所需的东西,该集合可以存储公式和范围。两者都可以相对于活动的工作表,也可以是绝对的。

最大的区别在于:

  
    

调用Thisworkbook.Names.Add(Name:=“ Bob”,RefersTo:= Range(“ Sheet2!$ F $ 19”))

  

  
    

致电Thisworkbook.Names.Add(Name:=“ Doug”,RefersTo:=“ Sheet2!$ F $ 19”)

  

如果移动了Sheet2上的单元格F19,则Bob将在工作簿中的任何位置引用新位置;将其移到新的工作表上,Bob将会跟进。但是无论如何,道格将永远引用Sheet2 F19。

然后引用只是[Bob]或Range(“ Bob”),并且如果需要,将引用除活动工作表之外的另一个工作表。

StackExchange注意到一个非常有趣的相关问题:

Excel VBA: Workbook-scoped, worksheet dependent named formula/named range (result changes depending on the active worksheet)

...这是工作簿级别的名称可以包含公式的位置,每张工作表中该公式的值之一可以与整个工作簿相同,也可以与一个本地值相关。实际上,您可以将两个公式混合在一起。

答案 1 :(得分:0)

您可以将名称范围存储到Enum中,然后在访问它们周围包装一个类。设置工作有些繁琐,但是,您可以根据需要使用某些VBA IDE编程来自动创建特定于现有工作簿的此类。

我没有做这部分,但是我正在分享可能有用的方法。

将此添加到类中,命名为NameRangeHelper

'Update these to correspond to the named ranges in your workbook, or
'those range you want access to with this approach
Public Enum NamedRanges
    Example1
    Example2
    Example3
End Enum

Private pNamedRanges As Object

Private Sub Class_Initialize()
    Dim NamedRange  As Name
    Dim NamedRanges As Names

    Set NamedRanges = ThisWorkbook.Names
    Set pNamedRanges = CreateObject("Scripting.Dictionary")

    For Each NamedRange In NamedRanges
        If Not pNamedRanges.Exists(NamedRange.Name) Then
            If TypeName(NamedRange.RefersToRange) = "Range" Then pNamedRanges.Add NamedRange.Name, NamedRange.RefersToRange
        End If
    Next

End Sub

Private Sub Class_Terminate()
    Set pNamedRanges = Nothing
End Sub

Public Function GetRange(RangeName As NamedRanges) As Excel.Range
    Dim RangeStringName As String
    RangeStringName = GetEnumName(RangeName)
    If pNamedRanges.Exists(RangeStringName) Then Set GetRange = pNamedRanges(RangeStringName)
End Function

Private Function GetEnumName(RangeName As NamedRanges) As String
    Select Case RangeName
        Case NamedRanges.Example1
            GetEnumName = "Example1"
        Case NamedRanges.Example2
            GetEnumName = "Example2"
        Case NamedRanges.Example3
            GetEnumName = "Example3"
        Case Else
            GetEnumName = vbNullString
    End Select
End Function

Public Function GetSheetFromRange(RangeName As NamedRanges) As Excel.Worksheet
    Set GetSheetFromRange = GetRange(RangeName).Parent
End Function

Public Function GetWorkbookFromRange(RangeName As NamedRanges) As Excel.Workbook
    Set GetWorkbookFromRange = GetRange(RangeName).Parent.Parent
End Function

这是客户端代码,以访问带有已定义枚举的范围为例。

 Sub ExampleNamedRangeHelper()
    Dim rngHelper As NamedRangeHelper: Set rngHelper = New NamedRangeHelper
    Dim rng       As Range
    Set rng = rngHelper.GetRange(Example1)
    Debug.Print rng.Address, rngHelper.GetSheetFromRange(Example1).Name, rngHelper.GetWorkbookFromRange(Example1).Name
End Sub

使用这种方法,您的名字在一个Enum中,并且您获得了Intellisense,可以更轻松地选择/记住范围名称。