2008-12-24 11 views
1

Eh bien, j'ai presque terminé la finalisation de la partie audit de mon application dont j'ai discuté here. La façon dont je le fais est de boucler tous les champs de texte, les listes déroulantes et les cases à cocher et de stocker leurs valeurs dans l'événement form_load. Ensuite, je fais la même chose dans l'événement form_afterUpdate et je compare les deux. S'il y a une différence je l'enregistre, sinon je continue. Voici le code:Pour chaque ne fonctionne pas correctement dans le code VBA

Dim strValues(1 To 32) As String 

Private Sub Form_AfterUpdate() 
    Dim strCurrentValue, strSQL As String 
    Dim intCurrentField As Integer 
    intCurrentField = 1 

    For Each C In Forms!frmVendorsManageVendors.Controls 
     Select Case C.ControlType 
      Case acTextBox, acComboBox, acCheckBox 
       //Doing this because I don't want a NULL as it won't concatenate in the SQL query and don't want 0 or -1 for the boolean fields 
       strCurrentValue = IIf(IsNull(C), "", IIf(C = vbTrue Or C = vbFalse, IIf(C = vbTrue, "Yes", "No"), C)) 

       If strValues(intCurrentField) <> strCurrentValue Then 
        strSQL = "INSERT INTO changesTable (change_time,user_affected,field_affected,old_value,new_value) VALUES (NOW()," & [id] & ",'" & C.ControlSource & "','" & strValues(intCurrentField) & "','" & strCurrentValue & "')" 

        DoCmd.SetWarnings False 
        DoCmd.RunSQL strSQL 
        //InputBox "", "", strSQL 
        strSQL = "WEEEE" 
        DoCmd.SetWarnings True 

        strValues(intCurrentField) = strCurrentValue 
       End If 

       intCurrentField = intCurrentField + 1 
     End Select 
    Next 
End Sub 

Private Sub Form_Open(Cancel As Integer) 
    Call btnLock_Click 

    Dim intCurrentField As Integer 
    intCurrentField = 1 

    For Each C In Forms!frmVendorsManageVendors.Controls 
     Select Case C.ControlType 
      Case acTextBox, acComboBox, acCheckBox 
       //Doing this because I don't want a NULL as it won't concatenate in the SQL query and don't want 0 or -1 for the boolean fields 
       strValues(intCurrentField) = IIf(IsNull(C), "", IIf(C = vbTrue Or C = vbFalse, IIf(C = vbTrue, "Yes", "No"), C)) 
       intCurrentField = intCurrentField + 1 
     End Select 
    Next 
End Sub 

Comme vous pouvez le voir, il y a une ligne de commentaire où insérer dans le changesTable qui va mettre la requête dans une zone de saisie, je peux copier/coller et regarder. Quand je décommente cette ligne, tout va bien. Si elle est commentée, elle génère la première modification, mais ne la modifie pas pour les autres contrôles. Donc, si je change field1 et field2, le champ 1 sera modifié deux fois.

Il est assez déroutant et je n'ai aucune idée de la raison pour laquelle cela se produit.

Je sais aussi que j'utilise la mauvaise syntaxe de commentaire, mais si j'utilise la syntaxe correcte, la "couleur de code" SO ne s'affiche pas correctement.

+0

Vous pouvez utiliser la syntaxe de commentaire correcte dans le code de démarquage en plaçant une autre apostrophe/guillemet simple à la fin du commentaire. Cela force le coloreur à penser que le commentaire est une chaîne de caractères, mais il permettra également de copier/coller votre code et de le laisser fonctionner. –

+0

Deux choses: 1. // n'est pas le délimiteur de commentaire de VBA, qui est l'apostrophe . Lorsque j'utilise // dans le code d'accès, il génère une erreur de compilation. 2. Vous ne semblez pas avoir déclaré C comme variable, ce qui suggère que vous n'avez pas OPTION EXPLICIT dans tous vos modules de code. C'est une pratique de codage * TERRIBLE *. –

+0

David vous devriez lire toute la question avant de commenter –

Répondre

0

Je suppose qu'AfterUpdate n'est peut-être pas le bon événement à utiliser. De plus, si vous placez inputbox, le contrôle existant perd son focus (ce qui le fait se comporter correctement).

Je suggère de vérifier que chacune de vos commandes est en cours d'exécution en mettant un msgbox C.name à l'intérieur de la boucle après sélection de cas.

+0

J'ai déjà fait beaucoup de tests msgbox tous les champs sont en cours d'exécution (et rappelez-vous que j'ai mentionné que cela fonctionne parfaitement si j'ajoute la zone de saisie intrusive) - mais je pense que vous peut être sur quelque chose avec le focus perdant ... –

1

Je ne suis pas sûr d'avoir toute la réponse, mais quelques observations.

Vous pouvez éliminer certaines lignes de code en utilisant CurrentDB.Execute strSQL. Cela élimine le besoin des appels SetWarnings. Il s'exécute directement sur la base de données sans interagir avec les mécanismes d'interface habituels. À des fins de débogage, il peut être préférable d'utiliser Debug.Print pour mettre votre chaîne SQL dans la fenêtre de débogage. Cela évite d'impliquer l'interface utilisateur et met toujours le code SQL là où vous pouvez le copier dans le presse-papiers si vous voulez l'attraper et travailler avec.

Je pense qu'il y a une faible chance que la méthode DoCmd appel pour exécuter votre SQL, même avec les appels à SetWarnnigs, pourrait basculer quelque chose dans l'interface pour retirer le focus du formulaire, comme suggéré par shahkalpesh. J'ai fait des choses comme ça et je n'ai pas vu le problème que vous avez, donc mon seul conseil sur le problème est de faire comme moi et de passer à CurrentDB.Execute et d'éliminer les appels à DoCmd dans la boucle.

Juste curieux - pourquoi avez-vous utilisé un tableau pour les valeurs précédentes plutôt que d'utiliser la propriété OldValue sur les contrôles?

0

Avez-vous essayé de le faire avec une instruction d'exécution (quelque chose comme ça)?

Dim db As DAO.Database 'Inside the transaction. 
Set db = CurrentDB 
strSQL = "INSERT INTO changesTable (change_time, user_affected, " & _ 
      "field_affected, old_value, new_value) VALUES (NOW()," & [id] & _ 
      ",'" & C.ControlSource & "','" & strValues(intCurrentField) & _ 
      "','" & strCurrentValue & "')" 
db.Execute strSql 
Questions connexes