2009-03-24 19 views
2

J'ai un ensemble de ComboBox dans une base de données MS Access 2003 qui sont tous liés à des champs dans une seule table. Cependant, les données qu'ils vous permettent de sélectionner ne proviennent pas de cette table et proviennent plutôt de diverses autres tables. Cela fonctionne bien pour l'histoire de la création d'enregistrements, mais maintenant je veux être en mesure de modifier l'enregistrement rétroactivement. Le problème est que je ne peux pas comprendre comment remplir les éléments de formulaire sans écrire un tas de code personnalisé. Mon objectif initial est de fournir une zone de liste déroulante qui limite vos choix pour enregistrer les ID, puis de faire une requête personnalisée et de l'utiliser pour définir les valeurs sélectionnées dans tous les différents éléments de formulaire. Cependant, je me sens comme si je devais être capable de faire quelque chose d'aussi simple que DoCmd.GoToRecord , , , ID et le formulaire devrait repeupler très bien. Je ne suis pas opposé à faire le travail occupé mais je suis sûr que je manque juste quelque chose dans ma connaissance relativement chétive de VBA et d'Access.Comment modifier les enregistrements d'un formulaire VBA que vous souhaitez sélectionner de manière interactive?

+0

Cette question est déroutante, si vous avez un formulaire standard avec des combos standard, il n'y a rien à faire ici, ça devrait juste marcher. – AnthonyWJones

+0

Essayez-vous de mettre à jour les éléments dans chaque zone de liste déroulante, car ils ont changé depuis le formulaire ouvert? – JeffO

Répondre

0

Je présume que vous avez déjà configuré les sources de ligne pour chaque zone de liste déroulante. Tant que vous n'avez pas limité la liste déroulante à cette liste; il devrait afficher ce que vous avez stocké dans cette colonne.

Cependant, si votre change Combo Box sa liste pour chaque ligne que vous pouvez faire quelque chose comme ça dans le cas OnCurrent enregistrement ou l'événement GotFocus du terrain:

Me.combo_box_name.Requery 
0

Après re-lecture de votre question, je pense que je voyez ce que vous essayez d'accomplir. Vous êtes sur la bonne voie avec GotoRecord, bien que j'utilise probablement OpenForm dans ce cas, car il a une propriété WhereCondition qui vous permet d'utiliser SQL pour spécifier exactement quel enregistrement ouvrir. Il semble que vous souhaitiez implémenter une fonctionnalité de type "Aller à l'enregistrement" dans votre formulaire, où l'utilisateur sélectionne un ID d'enregistrement dans une liste et le formulaire change pour afficher l'enregistrement sélectionné.

Une possibilité consiste à basculer vers le nouvel enregistrement chaque fois que l'utilisateur sélectionne un élément dans la zone de liste déroulante. Vous pouvez gérer cela dans l'événement Click du ComboBox.

Je vais utiliser un exemple simple: supposons que vous ayez une table Students et une StudentForm pour afficher/modifier des enregistrements dans la table Students. Le StudentForm a un ComboBox cboStudentID qui est lié à la colonne Students.ID via sa propriété RowSource. Lorsque vous sélectionnez un ID d'étudiant dans la zone de liste déroulante, le StudentsForm bascule pour afficher le dossier d'élève correspondant.

Dans le gestionnaire d'événements Click pour la zone de liste déroulante, vous pouvez coder ce « saut pour enregistrer » fonctionnalité avec quelque chose comme ce qui suit:

Private Sub cboStudentID_Click() 
    Dim recordID As Long 
    'The ItemData property will return the value of the bound' 
    'column at the specified index.' 
    recordID = cboStudentID.ItemData(cboStudentID.ListIndex) 
    'Jump to the record. This assumes we want to use the same form.' 
    'You can change the form name if you want to open a different form when' 
    'the user selects an ID from the ComboBox.' 
    DoCmd.OpenForm "StudentForm", WhereCondition:="Student.ID=" & recordID 
End Sub 

Comme David W. Fenton souligne dans les commentaires, vous pouvez raccourcir la ligne suivante:

recordID = cboStudentID.ItemData(cboStudentID.ListIndex) 

à ceci:

recordID = Me!cboStudentID 

ou tout simplement:

recordID = cboStudentID 

puisque la valeur par défaut du ComboBox dans ce cas, sera la valeur de la colonne liée à la ListIndex actuelle.Dans ce cas, vous pouvez simplement supprimer recordID tout à fait et le code de l'événement Click comme suit:

Private Sub cboStudentID_Click() 
    DoCmd.OpenForm "StudentForm", WhereCondition:="Student.ID=" & cboStudentID 
End Sub 
+0

Si la colonne ID est la colonne liée (indépendante du fait que la zone de liste déroulante soit liée ou non, c'est-à-dire, ControlSource), la valeur par défaut de la zone de liste déroulante est l'ID et inutile d'utiliser ItemData. Si vous avez besoin d'autre chose que la colonne liée, ItemData est juste le ticket. –

+0

Merci, David. J'ai édité ma réponse pour refléter le fait qu'ils sont équivalents dans ce cas. –

1

Juste pour ajouter au mélange, je propose deux approches, celle qui est recommandée, l'autre non. Approche 1: Si vous avez lié votre formulaire à l'ensemble de la table de données (c'est l'approche non recommandée), vous pouvez utiliser l'assistant de liste déroulante pour naviguer vers l'enregistrement demandé, mais je ne le recommanderais pas dans les versions récentes d'Access:

a. il ne vous permet pas de nommer correctement la zone de liste déroulante avant de créer du code.

b. le code est juste incorrect.

Voici le code que je viens produisais dans ma base de test:

Dim rs As Object 

Set rs = Me.Recordset.Clone 
rs.FindFirst "[InventoryID] = " & Str(Nz(Me![Combo2], 0)) 
If Not rs.EOF Then Me.Bookmark = rs.Bookmark 

Ceci est faux de tant de façons c'est tout simplement remarquable. C'est ce que le code devrait être:

With Me.RecordsetClone 
    .FindFirst "[ID]=" & Me!cmbMyComboBox 
    If Not .NoMatch Then 
    If Me.Dirty Then Me.Dirty = False 
    Me.Bookmark = .Bookmark 
    Else 
    MsgBox "Not Found!" 
    End If 
End With 

Il n'y a pas besoin de cloner le recordset du formulaire lorsque le RecordsetClone existe déjà.

Il n'y a aucune raison d'utiliser une variable d'objet lorsque vous pouvez utiliser directement l'objet préexistant.

Il doit y avoir une vérification pour un enregistrement sale avant de quitter l'enregistrement, car si vous ne forcez pas la sauvegarde, des erreurs dans le processus de sauvegarde peuvent conduire à des données perdues.

Mais la meilleure approche est la suivante:

Approche 2: Utilisez la zone de liste déroulante pour modifier recordsource sous-jacente du formulaire.

L'événement AfterUpdate de votre zone de liste déroulante ressemblerait à quelque chose comme ceci:

If Not IsNull(Me!cmbMyComboBox) Then 
    Me.Recordsource = Me.Recordsource & " WHERE [ID]=" & Me!cmbMyComboBox 
End If 

Maintenant, cela ne fonctionne que la première fois, comme sur la deuxième remise à zéro du Recordsource, vous vous retrouvez avec deux clauses WHERE, ce qui n'est pas bon. Il existe deux approches:

a. en supposant que la forme ouvre sans une clause WHERE, stocker la valeur recordsource d'ouverture dans une variable au niveau du module dans l'événement OnLoad du formulaire:

Private Sub Form_Load() 
    strRecordsource = Left(Me.Recordsource,Len(Me.Recordsource)-1) 
    End Sub 

Et au niveau du module, définir strRecordsource en conséquence:

Dim strRecordsource As String 

Puis à l'événement AfterUpdate de la zone de liste déroulante, vous avez ceci:

Me.Recordsource = strRecordsource & " WHERE [ID]=" & Me!cmbMyComboBox 

maintenant, si votre formulaire ouvre avec une clause WHERE déjà définie, cela devient plus compliqué, mais je n'entrerai pas là-dedans et je laisserai au lecteur le soin de déterminer quelle pourrait être la meilleure approche.

+0

Trouvé une faute de frappe mineure. Je pense que la ligne "rs.FindFirst ..." après le "With Me.RecordsetClone" dans votre deuxième exemple devrait lire ".FindFirst ...". –

+0

Oh, et +1. N'étant pas un gourou d'Access, je n'ai pas pensé à modifier directement la source d'enregistrements. Beaucoup plus élégant qu'un DoCmd, je pense. Peut-être que c'est juste moi et le fait que je ne fais pas vraiment la programmation Access, mais le recours à DoCmd me semble généralement être un hack (c'est-à-dire qu'il y a habituellement un meilleur moyen). –

+0

Merci pour la faute de frappe - maintenant corrigé. –