【问题标题】:How to change Named Range Scope如何更改命名范围范围
【发布时间】:2010-11-06 15:07:52
【问题描述】:

当我通过名称管理器创建命名范围时,我可以选择指定工作簿或[worksheet name] 范围。但是,如果随后想要更改范围,下拉菜单将显示为灰色。有没有办法在名称管理器或最好的 VBA 中更改现有命名范围的范围?

例如:

  • testName 指的是 'sheet1'!A1:B2 范围工作簿。我将如何将其更改为
  • testName 指的是 'sheet1'!A1:B2 范围为“sheet1”?

【问题讨论】:

    标签: vba excel


    【解决方案1】:

    我找到了解决方案!只需使用您的命名变量复制工作表。然后删除原来的工作表。复制的工作表现在将具有相同的命名变量,但具有本地范围(范围=复制的工作表)。

    但是,我不知道如何从局部变量更改为全局变量..

    【讨论】:

    • 谢谢朋友,我用过这个,效果很好。它将保留您的条件格式等,但如果您有宏代码,则不建议这样做。
    • 不错的快速解决方案,如果您想对所有名称应用相同的操作,这很有用。使用 Excel 2010,在删除原始工作表后,我留下了带有 Workbook 范围的原始名称(指向 #REF!...),但我可以快速删除它们。
    【解决方案2】:

    您可以从以下网址下载我和 Jan Karel Pieterse 开发的免费名称管理器插件 http://www.decisionmodels.com/downloads.htm 这实现了 Excel 2007 名称管理器无法处理的许多名称操作,包括更改名称范围。

    在 VBA 中:

    Sub TestName()
    Application.Calculation = xlManual
    Names("TestName").Delete
    Range("Sheet1!$A$1:$B$2").Name = "Sheet1!TestName"
    Application.Calculation = xlAutomatic
    End Sub
    

    【讨论】:

    • 此代码似乎将设置为工作簿的范围范围更改为工作表。我认为它应该做相反的事情。即将范围从工作表更改为工作簿。
    • 最初的问题对我来说似乎很清楚:“例如,'testName' 指的是 'sheet1'!A1:B2 范围为 Workbook。我如何将其更改为 'testName' 指的是 'sheet1' !A1:B2 具有 'sheet1' 范围?"
    • 请注意,如果您的工作表名称以数字开头或包含空格,则需要使用单引号对其进行转义 "'Sheet1'!TestName" 我建议始终在代码中转义名称。如果不需要,也不会伤害任何东西。
    • 微软已经为使用命名范围提供了这种必要的东西,这绝对是奇怪的。我们不应该在高级用户领域!
    • 您的名称管理器工具非常棒,Charles。不幸的是,我的公司新选择阻止安装第三方加载项。非常感谢您的帖子。
    【解决方案3】:

    查看这两个相互反转的子项,并翻转引用活动工作表上范围的所有命名范围的范围(工作表到工作簿或反转)。

     Option Explicit
    '---------------------------------------------------------------------------------------
    ' Procedure : RescopeNamedRangesToWorkbook
    ' Author    : JS20'07'11
    ' Date      : 11/18/2013
    ' Purpose   : Rescopes the parent of worksheet scoped named ranges to the active workbook
    ' for each named range with a scope equal to the active sheet in the active workbook.
    '---------------------------------------------------------------------------------------
    
    Public Sub RescopeNamedRangesToWorkbook()
    Dim wb As Workbook
    Dim ws As Worksheet
    Dim objName As Name
    Dim sWsName As String
    Dim sWbName As String
    Dim sRefersTo As String
    Dim sObjName As String
    Set wb = ActiveWorkbook
    Set ws = ActiveSheet
    sWsName = ws.Name
    sWbName = wb.Name
    
    'Loop through names in worksheet.
    For Each objName In ws.Names
    'Check name is visble.
        If objName.Visible = True Then
    'Check name refers to a range on the active sheet.
            If InStr(1, objName.RefersTo, sWsName, vbTextCompare) Then
                sRefersTo = objName.RefersTo
                sObjName = objName.Name
    'Check name is scoped to the worksheet.
                If objName.Parent.Name <> sWbName Then
    'Delete the current name scoped to worksheet replacing with workbook scoped name.
                    sObjName = Mid(sObjName, InStr(1, sObjName, "!") + 1, Len(sObjName))
                    objName.Delete
                    wb.Names.Add Name:=sObjName, RefersTo:=sRefersTo
                End If
            End If
        End If
    Next objName
    End Sub
    '---------------------------------------------------------------------------------------
    ' Procedure : RescopeNamedRangesToWorksheet
    ' Author    : JS20'07'11
    ' Date      : 11/18/2013
    ' Purpose   : Rescopes each workbook scoped named range to the specific worksheet to
    ' which the range refers for each named range that refers to the active worksheet.
    '---------------------------------------------------------------------------------------
    
    Public Sub RescopeNamedRangesToWorksheet()
    Dim wb As Workbook
    Dim ws As Worksheet
    Dim objName As Name
    Dim sWsName As String
    Dim sWbName As String
    Dim sRefersTo As String
    Dim sObjName As String
    Set wb = ActiveWorkbook
    Set ws = ActiveSheet
    sWsName = ws.Name
    sWbName = wb.Name
    
    'Loop through names in worksheet.
    For Each objName In wb.Names
    'Check name is visble.
        If objName.Visible = True Then
    'Check name refers to a range on the active sheet.
            If InStr(1, objName.RefersTo, sWsName, vbTextCompare) Then
                sRefersTo = objName.RefersTo
                sObjName = objName.Name
    'Check name is scoped to the workbook.
                If objName.Parent.Name = sWbName Then
    'Delete the current name scoped to workbook replacing with worksheet scoped name.
                    objName.Delete
                    ws.Names.Add Name:=sObjName, RefersTo:=sRefersTo
                End If
            End If
        End If
    Next objName
    End Sub
    

    【讨论】:

      【解决方案4】:

      另一种方法是“破解”2007 或更高版本的 Excel 文件,但建议您在这样做时要小心,并保留原始文件的备份:

      首先将 Excel 电子表格保存为 .xlsx 或 .xlsm 文件(不是二进制文件)。将文件重命名为 .zip,然后解压缩。转到 zip 结构中的 xl 文件夹,然后在写字板或类似的文本编辑器中打开 workbook.xml。命名范围可在 definedName 标记中找到。本地范围由 localSheetId="x" 定义(可以通过在 Excel 中按 Alt-F11 找到工作表 ID,打开电子表格,进入 VBA 窗口,然后查看“项目”窗格)。隐藏范围由 hidden="1" 定义,因此只需删除 hidden="1" 即可取消隐藏。

      现在重新压缩文件夹结构,注意保持文件夹结构的完整性,然后重命名为 .xlsx 或 .xlsm。

      如果您需要更改范围或隐藏/取消隐藏大量已定义范围,这可能不是最佳解决方案,尽管它可以很好地进行一两个小调整。

      【讨论】:

        【解决方案5】:

        从头开始创建新名称并删除旧名称。

        【讨论】:

        • 如果您碰巧有 100 个名字要更改,那就不是很好了
        【解决方案6】:

        在尝试使用Workbook 范围定义命名范围时,这些答案有助于解决类似问题。 “啊哈!”对我来说是使用与整个工作簿相关的Names Collection!这可能对许多人来说是显而易见的,但在我的研究中并没有明确说明,所以我分享给其他有类似问题的人。

        ' Local / Worksheet only scope
        Worksheets("Sheet2").Names.Add Name:="a_test_rng1", RefersTo:=Range("A1:A4")
        
        ' Global / Workbook scope
        ThisWorkbook.Names.Add Name:="a_test_rng2", RefersTo:=Range("B1:b4") 
        

        如果您在 Sheet2 处于活动状态时查看名称列表,则两个范围都存在,但切换到任何其他工作表,"a_test_rng1" 不存在。

        现在我可以很高兴地在我的代码中生成一个我认为合适的命名范围。无需乱用名称管理器或插件。


        除此之外,Excel Mac 2011 中的名称管理器一团糟,但我确实发现虽然没有列标签可以告诉您在查看命名范围列表时正在查看的内容,但如果列出了工作表除了名称之外,该名称的范围是工作表/本地。请参阅随附的屏幕截图。

        感谢this article 拼凑这些部分。

        【讨论】:

        • 终于有一个简单的解决方案了。谢谢!!
        【解决方案7】:

        以下是我将所有工作表名称提升为全局名称的方法。 YMMV

        For Each wsh In ActiveWorkbook.Worksheets
        For Each n In wsh.Names
            ' Get unqualified range name
            Dim s As String
            s = Split(n.Name, "!")(UBound(Split(n.Name, "!")))
            ' Add to "Workbook" scope
            n.RefersToRange.Name = s
            ' Remove from "Worksheet" scope
            Call n.Delete
        Next n
        Next wsh
        

        【讨论】:

        • 它似乎在 2013 年运行良好,但对于 2010 年及以下,您需要先定义这些变量:Dim wsh As Worksheet Dim N As Object
        • 这只是从该工作表中删除所有名称。删除前需要创建一个新的Name 引用相同的范围。
        【解决方案8】:

        这仍然需要进一步完善,但适用于所有简单的引用,而不会杀死现有的本地名称。

        Type GlobalNamesToLocalNames_Type
           Name As String
           Sheet As String
           Ref As String
        End Type
        
        Sub GlobalNamesToLocalNames(Optional Void As Variant)
           Dim List() As GlobalNamesToLocalNames_Type
           Dim Count As Long
           Dim Name As Name
           Dim Dat() As String
           Dim X As Long
        
           ' count the size
           For Each Name In ActiveWorkbook.Names
              Count = Count + 1
           Next
           ReDim List(Count - 1)
           Count = 0
        
           ' Collecect all name data
           For Each Name In ActiveWorkbook.Names
              With List(Count)
                 ' Pick up only the name
                 If InStr(Name.Name, "!") > 0 Then
                    Dat = Split(Name.Name, "!")
                    .Name = Dat(1)
                 Else
                    .Name = Name.Name
                 End If
                 ' pick up the sheet and refer
                 Dat = Split(Name.RefersTo, "!")
                 .Sheet = Mid(Dat(0), 2)
                 .Ref = Dat(1)
                 ' make local sheet name
                 .Name = .Sheet & "!" & .Name
              End With
              Count = Count + 1
           Next
        
           ' Delete all names
           For Each Name In ActiveWorkbook.Names
              Name.Delete
           Next
        
           'rebuild all the names
           For X = 0 To Count - 1
              With List(X)
                 If Left(.Ref, 1) <> "#" Then
                    ActiveWorkbook.Names.Add Name:=.Name, RefersToLocal:="=" & .Sheet & "!" & .Ref
                 End If
              End With
           Next
        End Sub
        

        【讨论】:

          【解决方案9】:

          对我来说,当我从 Name Manager 为同一范围创建 new Name tag 时,它可以让我选择更改范围;) 工作簿是默认的并且可以更改为任何可用的工作表。

          【讨论】:

          • 在 Office 365 中工作就像一个魅力。无需 VBA hack。
          【解决方案10】:

          JS20'07'11 的代码真是不可思议的简单直接。我想提出的一个建议是在条件中加上感叹号:

          InStr(1, objName.RefersTo, sWsName+"!", vbTextCompare)
          

          因为这将防止在不正确的工作表中添加 NamedRange。例如:如果 NamedRange 引用了一个名为 Plan11 的工作表,而您有另一个名为 Plan1 的工作表,则在添加范围时,如果你不用感叹号。

          更新

          更正:最好使用正则表达式评估工作表的名称。您可以使用的一个简单函数如下(改编自http://blog.malcolmp.com/2010/regular-expressions-excel-add-in,启用Microsoft VBScript Regular Expressions 5.5):

          Function xMatch(pattern As String, searchText As String, Optional matchIndex As Integer = 1, Optional ignoreCase As Boolean = True) As String
          On Error Resume Next
          Dim RegEx As New RegExp
          RegEx.Global = True
          RegEx.MultiLine = True
          RegEx.pattern = pattern
          RegEx.ignoreCase = ignoreCase
          Dim matches As MatchCollection
          Set matches = RegEx.Execute(searchText)
          Dim i As Integer
          i = 1
          For Each Match In matches
              If i = matchIndex Then
                  xMatch = Match.Value
              End If
              i = i + 1
          Next
          End Function
          

          所以,你可以使用类似的东西:

          xMatch("'?" +sWsName + "'?" + "!", objName.RefersTo, 1) <> ""
          

          而不是

          InStr(1, objName.RefersTo, sWsName+"!", vbTextCompare)
          

          这将涵盖 Plan1 和 'Plan1'(当范围涉及多个单元格时)变体

          提示:避免使用单引号 (')、:) 的工作表名称。

          【讨论】:

            【解决方案11】:

            我在 JS20'07'11 以前的 Makro 中添加了一些额外的代码行,以确保工作表的命名范围的名称不是工作簿的命名范围的名称。 如果没有这些行,已定义的工作簿铲取命名范围将被删除和替换。

            Public Sub RescopeNamedRangesToWorkbookV2()
            Dim wb As Workbook
            Dim ws As Worksheet
            Dim objNameWs As Name
            Dim objNameWb As Name
            Dim sWsName As String
            Dim sWbName As String
            Dim sRefersTo As String
            Dim sObjName As String
            Set wb = ActiveWorkbook
            Set ws = ActiveSheet
            sWsName = ws.Name
            sWbName = wb.Name
            
            'Loop through names in worksheet.
            For Each objNameWs In ws.Names
            
            
            'Check name is visble.
                If objNameWs.Visible = True Then
            'Check name refers to a range on the active sheet.
                    If InStr(1, objNameWs.RefersTo, sWsName, vbTextCompare) Then
                        sRefersTo = objNameWs.RefersTo
                        sObjName = objNameWs.Name
            'Check name is scoped to the worksheet.
                        If objNameWs.Parent.Name <> sWbName Then
            'Delete the current name scoped to worksheet replacing with workbook scoped name.
                            sObjName = Mid(sObjName, InStr(1, sObjName, "!") + 1, Len(sObjName))
            'Check to see if there already is a Named Range with the same Name with the full workbook scope.
                            For Each objNameWb In wb.Names
                                If sObjName = objNameWb.Name Then
                                MsgBox "There is already a Named range with ""Workbook scope"" named """ + sObjName + """. Change either Named Range names or delete one before running this Macro."
                                Exit Sub
                                End If
                            Next objNameWb
                            objNameWs.Delete
                            wb.Names.Add Name:=sObjName, RefersTo:=sRefersTo
                        End If
                    End If
                End If
            Next objNameWs
            End Sub
            

            【讨论】:

              【解决方案12】:

              在 theexceladdict.com 上找到了这个

              • 在工作表上选择要更改其范围的命名范围;

              • 打开名称管理器(公式选项卡)并选择名称;

              • 点击删除并确定;

              • 单击新建...,然后在名称字段中输入原始名称;

              • 确保将范围设置为工作簿,然后单击关闭。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2022-01-24
                • 1970-01-01
                • 1970-01-01
                • 2016-11-22
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多