【问题标题】:Get a Named Range by String in Excel Workbook when Name is duplicated名称重复时在 Excel 工作簿中按字符串获取命名范围
【发布时间】:2012-10-09 22:44:18
【问题描述】:

为了详细说明,假设我的工作簿中有两个命名范围。两个命名范围具有相同的名称(比如说“myName”),但一个范围限定为 Sheet1,另一个范围限定为工作簿。

给定命名范围的名称(字符串),我想获取工作簿级别的命名范围。

如果我使用本机调用:wb.Names.Item("myName"),它会返回工作表范围命名范围。

如果我这样做:wb.Names.Item("Sheet1!myName"),那显然会返回工作表范围的名称范围。我发现我可以使用它来指定特定工作表,但不能指定工作簿。

无论如何我可以指定我想要工作簿范围吗?

我的解决方法目前正在遍历所有名称的列表,并比较 .Name 属性以获取工作簿范围命名范围。这是因为 .Name 属性附加了一个“Sheet1!”。到工作表范围命名范围。然而,这样做成本很高,我想避免它。

【问题讨论】:

  • 我不是 100% 清楚你是如何使用这个范围的。如果您尝试将范围对象设置为名称字符串,那么Set rng1 = Range("myName") 将在 sheet1 处于活动状态时返回本地工作表名称的范围,否则它将返回工作簿名称的范围。我认为这是最干净的解决方法 - 即在将名称用作工作簿范围之前测试活动工作表与托管本地名称的工作表不同。有道理? :)
  • 您还可以将 parent.name 与工作簿名称进行比较,但您仍需要遍历名称以提取该集合。
  • 回复:@brettdj 的评论。根据您要实现的目标,最简单的方法可能是在宏的开头添加一个临时表,然后在代码末尾删除。
  • 不,不管你在哪张纸上。它首先返回工作表级别(如果存在多个工作表范围,则根据工作表排序进行排序)。如果不存在工作表范围的,则返回 wb 范围的。而且我不想设置范围。我只是想获得 COM 对象,这样我就可以对它做任何我需要做的事情。
  • @Shark,您能否一次性分析工作簿中的所有名称,然后将工作簿范围内的命名范围保存在字典中?这种类型的缓存似乎可以缓解任何性能问题。

标签: c# excel named-ranges


【解决方案1】:

当我们(JKP 和我自己)编写 Name Manager 时,我们专门为重复的全局/本地名称添加了过滤器和警告消息,因为您提到的这种 Excel 对象模型行为会导致难以检测到错误。

所以我的建议是永远不要使用重复的全局/本地名称。

我们使用代码来检测名称是否是重复的全局/本地名称,并且本地名称的父级处于活动状态,然后在必要时切换工作表。我们用来查找全局名称的本地版本的优化 VBA 代码是这样的:除非您有数万个名称,否则它相当快 -

    Function FindNameLocal(oSheet As Worksheet, sName As String) As Name
        Dim oName As Name
        Dim strLocalName As String
        Dim strLocalNameNoQuote
        Dim strName As String
        Set FindNameLocal = Nothing
        If Len(sName) > 0 And Not oSheet Is Nothing And oSheet.Names.Count > 0 Then
            On Error Resume Next
            strLocalName = "'" & oSheet.Name & "'!" & sName
            strLocalNameNoQuote = oSheet.Name & "!" & sName
            Set FindNameLocal = oSheet.Names(strLocalName)
            If Err <> 0 Or (FindNameLocal.NameLocal <> strLocalName And FindNameLocal.NameLocal <> strLocalNameNoQuote) Then
                On Error GoTo 0
                Set FindNameLocal = Nothing
                For Each oName In oSheet.Names
                    strName = oName.Name
                    If Len(strLocalName) = Len(strName) Or Len(strLocalNameNoQuote) = Len(strName) Then
                        If strName = strLocalName Or strName = strLocalNameNoQuote Then
                            Set FindNameLocal = oName
                            GoTo GoExit
                        End If
                    End If
                Next
            End If
        End If
GoExit:
    End Function

【讨论】:

  • 我不确定这是否能回答我的问题。也许我误读了它,但我需要获取名称的全球版本。这将返回第一级工作表,我已经可以通过以 wb.Names.Item("Sheet1!myName") 的格式传递它来做到这一点。我确实注意到你的代码中有一件我很好奇的事情。在比较字符串之前比较长度是否会大大提高性能?
  • 我们使用它通过传递全局名称和活动工作表名称来检测是否存在重复的全局-本地名称。如果有重复,那么您需要更改工作表并重试,直到找到不包含重复的工作表(或临时添加新工作表),这样当您访问名称时,您将获得全局名称。在 VBA 中获取字符串的长度非常快,但比较字符串很慢:不知道这在 C# 中适用的程度。
  • 啊,现在说得通了。我将不得不看看你的方法(翻译成 C#)是否比我想出的另一个想法更快。我将发布解决方案作为另一个答案。然后性能测试将决定获胜者!
  • 顺便说一句,如果您使用美国英语,您应该能够跳过 For Each 循环。
猜你喜欢
  • 1970-01-01
  • 2015-10-31
  • 2010-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-15
相关资源
最近更新 更多