2012-10-09 34 views
7

Elaborar, vamos a decir que tengo dos rangos con nombre en mi libro. Ambos rangos nombrados tienen el mismo nombre (digamos "myName"), pero uno tiene un alcance de Sheet1 y el otro tiene un ámbito en el Workbook.Obtener un rango con nombre de cadena en el libro de Excel cuando se duplica Nombre

Dado un nombre (cadena) del rango con nombre, quiero agarrar el nivel del libro denominado rango.

Si utilizo la llamada nativa: wb.Names.Item("myName"), devuelve la hoja de ámbito rango con nombre.

Si por el contrario lo hago: wb.Names.Item("Sheet1!myName"), que, obviamente, devuelve la hoja con ámbito rango nombre. He descubierto que puedo usar esto para especificar los específicos de la hoja, pero no uno de libro de trabajo.

¿Hay alguna forma de especificar Quiero el libro de ámbito uno?

Mi solución es actualmente la iteración en la lista de todos los nombres, y la comparación de la propiedad .Nombre para agarrar el alcance libro rango con nombre. Esto funciona porque la propiedad .Name agrega un "Sheet1!" a la hoja con alcance Named Range. Sin embargo, esto es muy costoso de hacer, y quiero evitarlo.

+2

No es 100% claro cómo se utiliza el distancia. Si estaba intentando establecer un objeto de rango en una cadena de nombre, 'Set rng1 = Range (" myName ")' devolverá el rango desde el nombre de la hoja local si * sheet1 está activo * else devolverá el rango del nombre del libro de trabajo . Creo que esta es la solución más limpia, es decir, probar que la hoja activa es diferente de la hoja que aloja el nombre local antes de buscar usar el nombre como el alcance del libro de trabajo. ¿Tener sentido? :) – brettdj

+0

también puede comparar parent.name con el nombre del libro de trabajo, pero aún necesita recorrer los nombres para extraer esa colección. – nutsch

+0

re: @ brettdj's comment. Dependiendo de lo que intente lograr, lo más fácil podría ser simplemente agregar una hoja temporal al comienzo de su macro, que se eliminará al final de su código. – nutsch

Respuesta

1

Cuando nosotros (JKP y yo) estábamos escribiendo Name Manager, agregamos específicamente un filtro y un mensaje de advertencia para Nombres Globales/Locales Duplicados porque este comportamiento del modelo de objetos de Excel que menciona conduce a errores difíciles de detectar.

Así que mi recomendación es nunca utilizar nombres globales/locales duplicados.

Utilizamos el código para detectar si un nombre es duplicado global/local con el padre del nombre local activo y luego cambiar las hojas si es necesario. El código VBA optimizado que usamos para encontrar la versión local de un nombre global es la siguiente: su razonablemente rápido a menos que tenga varias decenas de miles de nombres -

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 
+0

No estoy seguro de que esto responda mi pregunta. Tal vez estoy malinterpretando, pero necesito obtener la versión Global del nombre. Esto devuelve el nivel de hoja uno, que ya puedo hacer pasándolo en el formato de wb.Names.Item ("Sheet1! MyName"). Noté una cosa en su código que me causa curiosidad. ¿La comparación de la longitud antes de comparar cadenas provoca una gran ganancia de rendimiento? – Shark

+0

Usamos esto para detectar si hay un nombre global local duplicado al pasar el nombre global y el nombre de la hoja de trabajo activa. Si hay un duplicado, entonces necesita cambiar la hoja de trabajo e intentar nuevamente hasta que encuentre una hoja de trabajo que no contenga un duplicado (o agregue temporalmente una hoja nueva) para que luego, al acceder al nombre, obtenga la hoja global. Obtener la longitud de una cadena es muy rápido en VBA, pero la comparación de cadenas es lenta: no sé en qué medida esto se aplica en C#. –

+0

Ahh, tiene sentido ahora. Tendré que ver si su enfoque (traducido a C#) es más rápido que otra idea que se me ocurrió. Estaré publicando la solución como otra respuesta. ¡Entonces las pruebas de rendimiento determinarán el ganador! – Shark

Cuestiones relacionadas