Comment get / définir un identifiant unique pour la cellule dans Excel via VBA

Je souhaite avoir / définir un identifiant unique pour chaque ligne de données dans ma feuille de données Excel – afin que je puisse l'utiliser lors du passage des données et rest identique lorsque les lignes sont ajoutées / supprimées au-dessus.

Mes pensées sont d'utiliser l'atsortingbut ID de Range ( msdn link )

Donc, j'ai une fonction définie par l'user (UDF) que je place dans chaque ligne qui obtient / définit l'ID comme suit:

Dim gNextUniqueId As Integer Public Function rbGetId(ticker As Ssortingng) On Error GoTo rbGetId_Error Dim currCell As Range 'sortinged using Application.Caller direct, but gives same error Set currCell = Range(Application.Caller.Address) If currCell.id = "" Then gNextUniqueId = gNextUniqueId + 1 'this line fails no matter what value I set it to. currCell.id = Str(gNextUniqueId) End If rbGetId = ticker & currCell.id Exit Function rbGetId_Error: rbGetId = "!ERROR:" & Err.Description End Function 

Mais cela échoue à la ligne mentionnée avec

"Erreur définie par l'application ou définie par l'object"

Je pensais peut-être que c'est l'une de ces limitations des UDF, mais j'obtiens aussi la même erreur si je l'essaye à partir d'un code déclenché à partir d'un button de ruban …

D'autres suggestions sur la façon de conserver des identifiants cohérents – peut-être que je devrais localiser les cellules via mon button ruban, find des cellules sans ID et générer / définir la valeur de la cellule de celles-ci …

EDIT: Comme Ant pensait, j'ai la feuille protégée, mais même dans une cellule déverrouillée, elle échoue toujours. La désactivation de la feuille corrige le problème …. mais j'ai utilisé "Protect UserInterFaceOnly: = True" qui devrait me permettre de le faire. Si je autorise manuellement «Edit Objects» lorsque je protège la feuille, elle fonctionne également, mais je ne vois pas une option programmée pour cela – et je dois appeler la fonction Protect dans AutoOpen pour activer la fonction UserInterfaceOnly …

Je suppose que j'ai besoin d'éteindre / de protéger sur mon paramètre ID – en supposant que cela puisse être fait dans un UDF … ce qu'il semble qu'il ne peut pas, car cela ne fonctionne pas – ni ActiveSheet.unprotect ni ActiveWorkbook.unprotect 🙁

Merci d'avance. Chris

D'accord…

Il semble que si la feuille est verrouillée, les macros n'ont pas d'access en écriture à des informations de bas niveau telles que l'ID.

Cependant, je ne pense pas qu'il soit possible de déprotéger la feuille dans une UDF. Par design, les UDF sont fortement restreints; Je pense qu'avoir une formule de cellule de contrôle, la protection de la feuille romprait le paradigme de formule qu'une formule de cellule affecte une cellule seulement. Consultez cette page sur le site Web de Microsoft pour plus de détails.

Je pense que cela limite vos options. Vous devez:

  • renoncer à la protection des feuilles
  • abandonner l'UDF, utiliser un événement Worksheet_Change pour capturer les modifications de cellule et écrire à ID là-bas
  • utilisez un UDF qui écrit l'ID dans la valeur de la cellule plutôt que de l'save

L'approche UDF comporte des problèmes car vous essayez d'utiliser quelque chose conçu pour calculer une cellule pour faire une marque permanente sur la feuille.

Néanless, voici un exemple d'UDF que vous pouvez utiliser pour marquer une valeur "permanente" sur une cellule, qui fonctionne sur des cellules déverrouillées d'une feuille protégée. Celui-ci ne fonctionne que pour des cellules simples (bien qu'il puisse être adapté à une formule de tableau).

 Public Function CellMark() Dim currCell As Range Set currCell = Range(Application.Caller.Address) Dim myId As Ssortingng ' must be text; using .value will cause the formula to be called again ' and create a circular reference myId = currCell.Text If (Trim(myId) = "" Or Trim(myId) = "0") Then myId = "ID-" & Format(CStr(gNextUniqueId), "00000") gNextUniqueId = gNextUniqueId + 1 End If CellMark = myId End Function 

Cela est cependant tout à fait erroné. L'utilisation de la copy ou la boîte de remplissage conservera toutefois la valeur copiée précédente. Ce n'est qu'en définissant explicitement les cellules pour être une nouvelle formule. Mais si vous entrez la formule dans la cellule à nouveau (il suffit de cliquer dessus, appuyez sur ENTRÉE) une nouvelle valeur est calculée – ce qui est le comportement des cellules standard.

Je pense que l'événement Worksheet_Change est le path à parcourir, qui a beaucoup plus de latitude. Voici un exemple simple qui met à jour l'ID de tout changement de cellule. Il pourrait être adapté à votre scénario particulier. Cette fonction devrait être ajoutée à chaque feuille de calcul pour laquelle le comportement de configuration ID est nécessaire.

 Private Sub Worksheet_Change(ByVal Target As Range) Dim currCell As Range Set currCell = Target.Cells(1, 1) Dim currId As Ssortingng currId = currCell.ID If Trim(currCell.ID) = "" Then Target.Parent.Unprotect currCell.ID = CStr(gNextUniqueId) Target.Parent.Protect gNextUniqueId = gNextUniqueId + 1 End If End Sub 

Dernière note; Dans tous les cas, votre countur ID sera réinitialisé si vous rouvrez la feuille de travail (au less sous les détails limités présentés dans votre exemple).

J'espère que cela t'aides.

Concur avec Ant – votre code fonctionne bien ici sur Excel 2003 SP3.

J'ai également pu utiliser:

 Set currCell = Application.Caller If Application.Caller.ID = "" Then gNextUniqueId = gNextUniqueId + 1 'this line fails no matter what value I set it to. currCell.ID = Str(gNextUniqueId) End If 

Aha! Je pense que je l'ai.

Je pense que vous appelez cela à partir d'une formule de tableau, et il ne reçoit que l'ONCE avec toute la gamme. Vous ne pouvez pas get une ID pour une gamme – une seule cellule. Cela explique pourquoi Application.Caller.ID échoue pour vous, car Range ("A1: B9"). L'ID génère une Application-defined or object-defined error .

Lorsque vous utilisez Range(Application.Caller.Address) pour get la "cellule", vous devez simplement renvoyer cette erreur à la ligne currCell.ID .

Je pense que nous pouvons avoir quelques problèmes ici, mais je pense qu'ils testent des problèmes, pas des problèmes avec le code lui-même. Tout d'abord, si vous appelez la fonction à partir d'une autre chose que d'une cellule, comme la window immédiate, un autre code, etc. Application.Caller ne sera pas configuré. C'est ce qui génère l'erreur de votre object introuvable. Deuxièmement, si vous copyz / collez la cellule qui a la fonction, vous le feriez en copiant ou en collant l'ID. Donc là où vous le collez, la sortie rest la même. Mais si vous copyz simplement le text (au lieu de la cellule), puis collez, cela fonctionnera bien. (Y compris votre utilisation originale de Application.Caller.)

Le problème concerne Application.Caller.

Comme vous l'appelez à partir d'une fonction définie par l'user, il vous transmettra une description d'erreur. Voici la remarque dans le file d'aide.

Remarques

Cette propriété renvoie des informations sur la façon dont Visual Basic a été appelé, comme indiqué dans le tableau suivant.

Caller – Valeur de return

  • Une fonction personnalisée saisie dans une seule cellule – Un object Range spécifiant cette cellule
  • Une fonction personnalisée qui fait partie d'une formule de tableau dans une gamme de cellules – Un object Range spécifiant cette gamme de cellules
  • Une campagne Auto_Open, Auto_Close, Auto_Activate ou Auto_Deactivate – Le nom du document en tant que text
  • Une macro définie par la propriété OnDoubleClick ou OnEntry: le nom de l'identificateur d'object graphique ou la reference de la cellule (le cas échéant) auquel s'applique la macro
  • La boîte de dialog Macro (menu devises) ou tout appelant non décrit ci-dessus – Le #REF! valeur d'erreur

Étant donné que vous l'appelez à partir d'une fonction définie par l'user, ce qui se passe est Application.Caller renvoie une string d'un code d'erreur à votre variable VariaCell de plage. Il ne provoque pas une erreur que votre gestionnaire d'erreur reprendrait. Que se passe-t-il après que vous faites reference curCell, ce n'est plus une gamme. Sur ma machine, il tente de configurer curCell = Range ("Error 2023"). Quel que soit cet object, il ne peut plus avoir d'atsortingbut ID et lorsque vous essayez de le configurer, vous lancerez cette erreur d'object.

Voici ce que j'essayerais …

  1. Essayez de supprimer votre gestionnaire d'erreur et de voir si VBA lance des exceptions sur Range (Application.Caller.Address). Cela ne le réparera pas, mais cela pourrait vous indiquer la bonne direction.

  2. Soit par la logique ou Application.ActiveCell, soit, comme vous le souhaitez, faites reference directement à la cellule. Par exemple Range ("A1") ou Cells (1,1). Application.Caller.Address ne semble pas être une bonne option à utiliser.

  3. Essayez d'utiliser Option Explicit. Cela pourrait faire en sorte que la ligne où vous définissez curCell lance une erreur puisque Range (Application.Caller.Address) ne ressemble pas à une distance passante, ce qui est le type de données de CurCell.

J'ai trouvé que si je protège la feuille avec "Protect DrawingObjects: = False", l'UDF peut définir l'Id. Étrange.

Merci de votre aide.