2009-08-05 10 views
0

Je suis un peu confus au sujet de la portée des plages nommées dans Excel. J'ai deux versions d'un classeur Excel. Parfois, les utilisateurs doivent copier les données d'une ancienne version du classeur dans une version plus récente. Certaines fonctions VBA personnalisées sont utilisées dans la plupart des calculs de cellules. Chacune de ces fonctions recherche environ 4 à 12 plages nommées sur la feuille. Cela semblait bien fonctionner ... Cependant, j'ai récemment découvert que lorsque deux versions du fichier sont ouvertes, les références VBA à toutes les plages nommées ne renvoient les valeurs qu'à partir du premier fichier qui a été ouvert (donc si la version plus récente de le formulaire a été ouvert en premier, puis l'ancienne version va agir comme certaines de ses données proviennent de la nouvelle version!). Les plages nommées du deuxième fichier semblent être ignorées par le second fichier, au moins dans le code VBA, tant que les deux fichiers restent ouverts. Si je ferme le classeur ouvert en premier, le second calculera correctement.Les plages nommées en double entre les classeurs provoquent des confusions dans mes fonctions personnalisées

J'ai trouvé une solution partielle: au lieu de le faire:

Blah = Range("valueXYZ").Value 

Je le fais à la place:

Blah = ThisWorkbook.Names("namedCellXYZ").RefersToRange.Value 

Cela fonctionne très bien, mais seulement sur la version plus récente du classeur. Je ne peux pas mettre à jour le code VBA dans l'ancienne version du classeur. Cela signifie que si les clients ouvrent l'ancienne version après que la nouvelle version est déjà ouverte, (donc les deux sont ouverts, mais l'ancien a été ouvert en second), l'ancienne version obtiendra les valeurs et les plages nommées de la version plus récente - et Rapportez donc des nombres et des plages incorrects. C'est mauvais. J'ai besoin d'un bon moyen d'empêcher l'ancienne feuille d'accéder aux plages nommées à partir du nouveau, mais je ne peux que modifier le nouveau. La seule chose que je peux penser est de renommer toutes les plages nommées et mettre à jour beaucoup de code VBA dans la nouvelle version - quelque chose qui est sujette aux erreurs et sonne comme un travail excessif.

Des suggestions? Par exemple, est-il possible d'afficher au moins un avertissement à l'utilisateur lorsque le second fichier est ouvert? Ou est-il possible d'utiliser VBA pour restreindre la portée des plages nommées? D'autres idées?

Répondre

1

Vous pouvez essayer de gérer le WorkbookOpen Event dans la fenêtre de code "ThisWorkbook". Lorsque la nouvelle version du classeur est ouverte, vous pouvez parcourir tous les classeurs ouverts et voir si les anciennes versions sont dans la liste. Si oui, avertissez l'utilisateur que les valeurs de l'ancienne version de la feuille de calcul peuvent être incorrectes car les données sont lues dans la version la plus récente.

+0

Bonne idée. Cependant, j'ai de la difficulté à faire fonctionner ce gestionnaire d'événements. –

+0

Je l'ai fait fonctionner - j'ai dû redémarrer Excel pour que l'événement commence à fonctionner. Merci!!Pour autant que je sache, la version la plus récente n'a pas besoin de vérifier les classeurs qui sont déjà ouverts - le premier classeur ouvert a la priorité de toute façon (donc si l'ancienne version est ouverte en premier, les plages nommées fonctionnent correctement pour cela, et la nouvelle version est conçue correctement pour que cela fonctionne) (Ainsi, c'est seulement un problème si les anciennes versions sont ouvertes en second lieu). J'ai donc seulement besoin de mettre en place la fonction pour vérifier les classeurs qui s'ouvrent après le plus mis à jour. –

+0

Oui, cela a du sens. Si l'utilisateur ouvre Ancien, Nouveau, Ancien se référera à Ancien (premier ouvert) et Nouveau se référera à Nouveau (références complètes) - donc pas de problème. Si l'utilisateur ouvre Nouveau puis Ancien, l'utilisateur doit être averti. Si vous voulez aller encore plus loin, vous pouvez afficher l'avertissement, puis demander à l'utilisateur s'il est acceptable de fermer et de rouvrir New pour résoudre le problème. S'il existe des modifications non enregistrées dans Nouveau, l'utilisateur doit enregistrer, ne pas enregistrer ou annuler. – devuxer

0

[Modifier]

Ce sous vous dira si vous avez double plages nommées dans les classeurs ouverts. Comme l'a dit DanThMan, vous pouvez consulter dans le module objet ThisWorkbook:

Sub CheckRangeDups() 
    Dim wb As Workbook 
    Dim nm As Name 
    Dim count As Integer, i As Integer 
    Dim arrNm() As String 
    Dim dup As Boolean 
    Dim rngChk As Range 

    ReDim arrNm(0) 
    'cycle through workbooks' 
    For Each wb In Workbooks 
     'cycle through names in workbook' 
     For Each nm In wb.Names 
      'check if name refers to a range' 
      On Error Resume Next 
      Set rngChk = Nothing 
      Set rngChk = nm.RefersToRange 
      On Error GoTo 0 
      If Not rngChk Is Nothing Then 
       dup = False 
       'check if name in array of names' 
       For i = 0 To UBound(arrNm) 
        If nm.Name = arrNm(i) Then 
         MsgBox "Named range " & nm.Name & " duplicated." 
         dup = True 
         Exit For 
        End If 
       Next i 
       'if not then add it' 
       If Not dup Then 
        arrNm(count) = nm.Name 
        count = count + 1 
        ReDim Preserve arrNm(count) 
       End If 
      End If 
     Next nm 
    Next wb 
End Sub 

[/ Modifier]

Si je vous comprends bien, la qualification pleinement à vos références aux gammes vont résoudre votre problème. Exemple: Avec deux fichiers ouverts nommés fichier1 et fichier2, nommez la cellule A1 sur la feuille 1 "arange" dans les deux fichiers. Dans fichier1 tapez "fichier1" dans la cellule, sur fichier2 tapez "fichier2" dans la cellule. Exécutez maintenant ceci:

Sub whichRange() 
    Dim f1 As Workbook, f2 As Workbook 
    Set f1 = Workbooks("file1.xls") 
    Set f2 = Workbooks("file2.xls") 
    Dim s1 As Worksheet, s2 As Worksheet 
    Set s1 = f1.Worksheets(1) 
    Set s2 = f2.Worksheets(1) 

    Dim r1 As Range, r2 As Range 
    Set r1 = s1.Range("arange") 
    Set r2 = s2.Range("arange") 

    Debug.Print "WB: "; f1.Name; " cell: "; r1.Name; " contents: "; r1 
    Debug.Print "WB: "; f2.Name; " cell: "; r2.Name; " contents: "; r2 
End Sub 

La qualification complète permet à Excel de savoir à qui vous faites référence.

+1

Qualifier complètement tous les noms serait certainement une bonne idée pour toutes les futures versions, mais si je comprends bien l'OP, il y a déjà une ancienne version avec des macros qui ne peuvent pas être changées (elles sont déjà sur l'ordinateur de l'utilisateur). – devuxer

+0

J'ai déjà décrit comment je fais essentiellement la même chose pour la nouvelle version du classeur. Voir le deuxième exemple de code que j'ai collé ci-dessus - mon exemple de code a le bonus supplémentaire qu'il ne dépend pas de connaître la feuille de calcul où réside la plage nommée. De plus, DanThMan a raison - j'ai besoin de quelque chose pour travailler rétroactivement, ou au moins avertir les utilisateurs du problème. –

+0

Je peux déjà vérifier les plages nommées remplacées avec "if Range (" nameXYZ "). Value <> ThisWorkbook.Names (" nameXYZ "). RefersToRange.Value" dans une boucle for "pour chaque nm dans thisworkbook.names". Et encore une fois, je ne peux tout simplement pas faire ce travail rétroactivement, et finalement je répète que le deuxième exemple de code dans mon post original contourne le problème dans la version plus récente - ainsi, je n'ai pas besoin de détecter les doublons. En d'autres termes, j'apprécie vos efforts, mais vous ne résolvez pas le bon problème. –

Questions connexes