j'aimerais savoir s'il est possible d'utiliser la fonction Application.Run() sur une méthode publique de classe.
J'ai fait quelques essais, et si c'est possible, je ne trouve pas la bonne syntaxe.
Bonjour.
Je pense que ce n'est absolument pas possible.
Mais il est possible d'en invoquer une dans une Sub d'un module standard, qui, elle, peut être exécutée par un Application.Run
Dranreb, effectivement, mais ça impliquerait pour moi d'avoir autant de méthodes dans mon module standard que de classes que j'ai pensé utiliser la fonction Run sur une classe directement. Toutes ces classes possèdent une méthode Update, et j'aimerais pouvoir exécuter cette méthode avec uniquement un paramètre texte qui correspond au nom de la classe.
Pour le moment je me goinfre un Select Case horrible, mais ça me paraît sale.
VB:
Public clsNom1 As New clsNom1
Public clsNom2 As New clsNom2
Public clsNom3 As New clsNom3
Public Sub UpdateMappingClass(ByVal ClassName As String)
Select Case ClassName
Case "clsNom1": Call clsNom1.Update
Case "clsNom2": Call clsNom2.Update
Case "clsNom3": Call clsNom3.Update
End Select
End Sub
Toutes mes recherches pointent vers une impossibilité pour ma question. Je vais quand même faire le test avec une méthode de classe statique, on sait jamais.
Edit : c'est la classe qui est statique (Attribute VB_PredeclaredId = True). Test effectué. Ça ne fonctionne pas non plus.
Il serait possible de ranger vos objets dans un Dictionary ou une collection, dont les arguments ClassName possibles seraient les clés. C'est un peu ce que fait Excel pour tous les objets représentant ses entités, au fond. Une question en passant: êtes vous sûr qu'il vous faille des classes différentes ? (ça sent plutôt les exemplaires différents d'une même classe)
En fait, ces classes me permettent de gérer tous les ListObjects de mon classeur, moyennant certaines règles.
A chaque ListObject du classeur est associé une classe. L'objectif entre autres de ces classes est de rendre les intitulés de champs de tous les ListObjects de mon classeur accessibles via des propriétés. Donc dans toutes mes classes associées à un ListObject, nommé comme ledit objet, j'ai l'architecture suivante :
VB:
Option Explicit
' clsListObject : classe personnalisée de gestion/manipulation des ListObject en variable tableau
Private mList As New clsListObject
Private Sub Class_Initialize()
'Vérifications diverses + appel de la réinitialisation de mList pour mettre le tableau en mémoire
Call CheckMappingClass(Me): Call Me.Update
End Sub
Public Sub Update()
Set mList = Nothing: Call mList.Initialize(GetListObjectByName(TypeName(Me)))
' GetListObjectByName => peu importe où se trouve le ListObject dans le classeur.
' S'il est nommé correctement (c'est à dire comme une classe existante),
' la fonction le trouve en fonction de son nom et l'affecte à mList.
End Sub
Public Property Get List() As clsListObject
Set List = mList 'Default Property (Attribute List.VB_UserMemId = 0)
End Property
Private Sub Class_Terminate()
Set mList = Nothing
End Sub
A la suite de ce tronc commun, dans chaque classe, j'ai la liste des intitulés de champs. Par exemple dans une classe j'aurai ça :
VB:
Public Property Get Position(): Let Position = "Position": End Property
Public Property Get Slide(): Let Slide = "Slide": End Property
Public Property Get Description(): Let Description = "Description": End Property
Public Property Get HowMany(): Let HowMany = "How many": End Property
Et dans une autre classe j'aurai ça :
VB:
Public Property Get Name(): Let Name = "Name": End Property
Public Property Get Worksheet(): Let Worksheet = "Worksheet": End Property
Public Property Get FirstFieldIsUnique(): Let FirstFieldIsUnique = "First field is unique": End Property
Public Property Get MergedTitle(): Let MergedTitle = "Merged title": End Property
Donc quand je disais "moyennant certaines règles", je dois faire attention à ce que mes ListObjects n'utilisent pas des mots réservés de VBA, comme "Currency", ou "Optional", etc. (toutes mes classes associées à un ListObject sont créées par macro).
Tout ceci me permet d'accéder aux contenus de tous mes ListObject très simplement dans mon code.
Exemples :
VB:
Dim strDescription As String
dim strSlideType As String
' Méthode 1
With lsoSlides
Let strDescription = .List(i, .Description) ' Où "Description" est un intitulé de champ du ListObject "lsoSlides"
Let strSlideType = .List(i, .SlideType) ' Où "Slide type" est un intitulé de champ du ListObject "lsoSlides"
End With
' Méthode 2
Let strDescription = lsoSlides(i, lsoSlides.Description)
Let strSlideType = lsoSlides(i, lsoSlides.SlideType)
' En effet, ma classe clsListObject (mList) possède une propriété
' par défaut Item(ByVal i As Long, ByVal Header As String) As Variant
' comme pour la propriété List. Donc à partir de la classe, je peux
' directement passer à la propriété Item.
Par ailleurs, dans la mesure où je n'utilise pas de texte mais une méthode pour accéder à une colonne spécifique d'un champ, si je décide de modifier un intitulé de champs, j'ai juste à mettre à jour mon "Mapping" (mise à jour auto avec une macro). Ainsi le nom de la méthode sera modifié dans la classe, mais pas dans le code appelant. Il m'est alors facile de corriger tous les endroits comportant l'ancien intitulé en lançant une compilation qui m'affiche nécessairement les erreurs de code.
Voilà voilà... Une réponse un peu longue à ta question.
Je ne comprends pas du tout ce que ça apporte de plus que la simple utilisation de la collection ListColumns de chaque ListObject, dont chaque membre est un ListColumn, muni de propriétés Range, DataBodyRange et HeaderRowRange.
La différence, c'est que dans un cas tu vas avoir un appel de type
VB:
Let strValue = lsoListObject.ListColumns("Champ").DataBodyRange(Row).Value
' alternative
Let strValue = lsoListObject.ListRows(Row).Range(, lsoListObject.ListColumns("Champ").Index).Value
Et dans l'autre cas
VB:
Let strValue = clsListObject(Row, clsListObject.Champ)
L'intellisense te propose d'emblée tous les champs. Et si tu renommes ta méthode "Descripton" dans ta classe en "Description" par exemple, au moment de compiler, tu as l'alerte "Erreur de compilation : Membre ou méthode de données introuvable" qui t'emmène successivement sur tous les appels "[...].Descripton" qu'il faut corriger en "[...].Description".
Quand tu as dans un classeur jusqu'à une centaine de ListObjects (je m'en approche sur certains projets) avec pléthore de colonnes, et qu'il est demandé de modifier un intitulé de champ, je trouve ça confortable.
Par ailleurs, je mets tous mes ListObjects dans une classe personnalisée qui les manipule dans des variables tableau, donc beaucoup plus rapide en lecture comme en écriture.
La seule autre solution si vous ne voulez pas mettre vos objets dans une collection, c'est de spécifier en argument ByVal l'objet lui même que vous voulez traiter au lieu de son nom.
Il serait même possible de lui donner un nom de type défini par un module de classe d'interface prévoyant au moins votre méthode Update. Voir instruction Implements si vous voulez …
Mais ça ne va pas non plus si vous voulez l'exécuter par Application.Run. Là je ne vois que la collection.
Je pense que je ne me suis pas fait comprendre.
La manipulation de mes ListObject est beaucoup rapide avec les méthode que j'utilise en ce moment dans ma classe personnalisée (clsListObject) qu'en utilisant les propriété et méthodes de l'objet Excel.ListObject, et c'est indépendant de la question initialement posée.
Je travaille toujours avec des tableaux dynamiques soit sur un ListRow.Range.Value soit sur le ListObject.DataBodyRange.Value. C'est rapide et je n'ai jamais eu besoin d'autre chose.
=>dionysos
Pourquoi ne mets-tu à disposition un fichier Excel où est implémentée ta classe personnalisée (clsListObject) ?
1) pour qu'on y voit plus clair
2) pour le partage des connaissances entre XLDiens
Une fois de plus, je pense que je ne me fais pas comprendre. Et on a totalement dévié de la question de départ, mais c'est pas bien grave. D'ailleurs je l'avais en fait mal formulée. J'ai des classes statiques (je modifie la classe dans un éditeur texte et passe l'attibute VB_PredeclaredId à True), et je me demandais juste si je pouvais appeler une méthode de ma classe avec un appel de type Application.Run("MaClass.MaMethode").
La réponse est a priori non donc.
l'aces par un object classe de substitution ne peut en aucun cas etre plus rapide que par les propriété implémentées c'est tout bonnement impossible pour la simple et bonne raison que tes classe servent tout simplement de passerelle qui elle meme utilise forcement l’implémentation
patricktoulon, tout dépend de ce qu'on fait dans la classe de substitution et quelles sont les propriétés et méthodes dont on se sert couramment. Je pense que le fichier joint t'en persuadera. Incrémenter 6000 valeurs de 1 dans un tableau structuré à l'aide des méthodes natives est beaucoup plus long que de le faire dans une variable tableau (initialisée à partir du DataBodyRange d'un ListObject, puis "replaquée" sur le DataBodyRange pour appliquer les modifications).
Pourquoi ne mets-tu à disposition un fichier Excel où est implémentée ta classe personnalisée (clsListObject) ?
1) pour qu'on y voit plus clair
2) pour le partage des connaissances entre XLDiens
Je pourrais mais ce serait hors sujet sur ce topic, et il serait nécessaire que je commente tout mon code, ce que je n'ai pas encore pris le temps de faire , mais si vraiment ça t'intéresse, n'hésite pas à me dire ça en MP, et je me ferai un joie de partager. En tout cas le fichier exemple me demandera beaucoup de boulot... Par ailleurs, le fichier joint est un très bref aperçu de ce que ma classe clsListObject a la prétention de faire.