Как вы редактируете записи из формы VBA, которую вы хотите выбрать в интерактивном режиме? - PullRequest
2 голосов
/ 24 марта 2009

У меня есть набор ComboBox в БД MS Access 2003, все они связаны с полями в одной таблице. Тем не менее, данные, которые они позволяют вам выбирать, поступают не из этой таблицы, а из разных других таблиц. Это прекрасно работает для истории создания записи, но теперь я хочу иметь возможность редактировать запись задним числом. Проблема в том, что я не могу понять, как заполнять элементы формы, не написав кучу собственного кода.

Вначале я хотел предоставить поле со списком, ограничивающее ваш выбор записью идентификаторов, а затем выполнить собственный запрос и использовать его для установки выбранных значений во всех различных элементах формы. Тем не менее, я чувствую, что должен быть в состоянии сделать что-то столь же простое, как DoCmd.GoToRecord , , , ID, и форма должна заполняться просто отлично. Я не против делать занятую работу, но я уверен, что мне чего-то не хватает в моих относительно слабых знаниях VBA и Access.

Ответы [ 3 ]

1 голос
/ 25 марта 2009

Просто, чтобы добавить к миксу, я бы предложил два подхода, один рекомендованный, другой нет.

Подход 1. Если вы связали свою форму со всей таблицей данных (это не рекомендуемый подход), вы можете использовать мастер комбинированного окна для перехода к запрошенной записи, но я бы не рекомендовал ее использовать в последние версии Access:

а. он не позволяет правильно назвать поле со списком, прежде чем он создаст код.

б. код просто НЕПРАВИЛЬНЫЙ.

Вот код, который я только что создал в моей тестовой базе данных:

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

Это неправильно во многих отношениях, это просто замечательно. Вот какой код должен быть:

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

Нет необходимости клонировать набор записей формы, когда RecordsetClone уже существует.

Нет смысла использовать переменную объекта, если вы можете просто напрямую использовать уже существующий объект.

Перед удалением записи должна быть проверка на грязную запись, потому что если вы не принудительно сохраните данные, ошибки в процессе сохранения могут привести к потере данных.

Но лучший подход заключается в следующем:

Подход 2: Используйте поле со списком, чтобы изменить базовый источник записей формы.

Событие AfterUpdate вашего поля со списком будет выглядеть примерно так:

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

Теперь, это работает только в первый раз, так как при второй перезагрузке Источника записей вы получите два предложения WHERE, что не очень хорошо. Есть два подхода:

а. предполагая, что форма открывается без предложения WHERE, сохраните значение источника записей открытия в переменной уровня модуля в событии OnLoad формы:

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

А на уровне модуля, соответственно, определить strRecordsource:

   Dim strRecordsource As String

Затем в событии AfterUpdate поля со списком у вас есть это вместо:

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

Теперь, если ваша форма открывается с уже определенным предложением WHERE, она усложняется, но я не буду вдаваться в подробности и оставлю читателю в качестве упражнения наилучший подход.

0 голосов
/ 24 марта 2009

Перечитав ваш вопрос, я думаю, что вижу, чего вы пытаетесь достичь. Вы на правильном пути с GotoRecord, хотя я бы, вероятно, использовал OpenForm в этом случае, потому что у него есть свойство WhereCondition, которое позволяет вам использовать SQL, чтобы точно указать, какую запись открыть. Похоже, вы хотите реализовать в форме функциональность типа «перейти к записи», когда пользователь выбирает идентификатор записи из списка, и форма изменяется для отображения выбранной записи.

Одна возможность - переключаться на новую запись каждый раз, когда пользователь выбирает элемент в ComboBox. Вы можете справиться с этим в событии ComboBox Click.

Я буду использовать простой пример: предположим, у вас есть таблица Students и StudentForm для просмотра / редактирования записей в таблице Students. StudentForm имеет ComboBox cboStudentID, который связан со столбцом Students.ID через его свойство RowSource. Когда вы выбираете идентификатор студента в ComboBox, StudentsForm переключится на отображение соответствующей записи студента.

В обработчике событий Click для ComboBox вы можете кодировать эту функцию «перейти к записи» примерно следующим образом:

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

Как отметил Дэвид У. Фентон в комментариях, вы можете сократить следующую строку:

recordID = cboStudentID.ItemData(cboStudentID.ListIndex)

на это:

recordID = Me!cboStudentID

или просто:

recordID = cboStudentID

, поскольку значением ComboBox по умолчанию в этом случае будет значение привязанного столбца на текущем ListIndex. В этом случае вы можете просто удалить recordID и закодировать событие Click следующим образом:

Private Sub cboStudentID_Click() 
    DoCmd.OpenForm "StudentForm", WhereCondition:="Student.ID=" & cboStudentID
End Sub
0 голосов
/ 24 марта 2009

Я предполагаю, что вы уже настроили источники строк для каждого поля со списком. Пока вы не ограничили поле со списком этим списком; он должен отображать то, что вы сохранили в этом столбце.

Однако, если ваше поле со списком меняет свой список для каждой строки, вы можете сделать что-то подобное в событии OnCurrent записи или в событии GotFocus поля:

Me.combo_box_name.Requery 
...