Сохранение изменений в многозначном ComboBox через AuditTrail
У меня есть база данных Access 2010, использующая многозначное поле (встроенный способ доступа, чтобы иметь отношение m:n между двумя таблицами).
Для отслеживания изменений в базе данных я использую процедуру AuditTrail VBA каждый раз, когда обновляется соответствующая форма, сохраняя все изменения в таблице истории.
Теперь, когда я изменяю значение ComboBox и цикл достигает ComboBox, привязанного к многозначному полю, процедура выдает ошибку из-за несовместимых типов данных:
For Each ctl In Screen.ActiveForm.Controls
If ctl.Tag = "History" Then
If Nz(ctl.Value) <> Nz(ctl.OldValue) Then
With rst
.AddNew
![timestamp] = datTimeCheck
![UserName] = strUserID
![FormName] = Screen.ActiveForm.Name
![recordid] = Screen.ActiveForm.Controls(IDField).Value
![FieldName] = ctl.ControlSource
![beforeValue] = ctl.OldValue
![afterValue] = ctl.Value
.Update
End With
End If
End If
Next ctl
Как я могу получить фактический Value
и OldValue
из выпадающего списка, преобразованного в строку в VBA?
Я старался combobox.focus
а потом combobox.Text
Это работает, но не помогает с OldValue
проблема.
Как правильно использовать value
а также oldvalue
свойство комбобоксов? Официальная ссылка на объект VBA для комбинированных списков не помогает вообще. https://msdn.microsoft.com/en-us/library/office/ff821691.aspx
2 ответа
Это не элегантное решение, а быстрый и грязный обходной путь:
Измените ваш код так, чтобы он проверял по-разному ComboBox1 и другие элементы управления. .Value
а также .OldValue
в основном массив вариантов.
Dim afterValue as variant
Dim beforeValue as Variant
For Each ctl In Screen.ActiveForm.Controls
If ctl.Tag = "History" Then
If Ctl.name = "ComboBox1" then
err.clear
on error resume next
I=0
afterValue = ""
beforeValue = ""
while err=0
'
' Throws an error if 'out of range', i.e. after the last value
'
afterValue = afterValue + Nz(Cstr(ComboBox1.Value(I))) + ";"
beforeValue = beforeValue + Nz(Cstr(ComboBox1.OldValue(I))) + ";"
wend
else
afterValue = ctl.Value
beforeValue = Nz(ctl.OldValue)
endif
If Nz(ctl.Value) <> a$ Then
With rst
.AddNew
![timestamp] = datTimeCheck
![UserName] = strUserID
![FormName] = Screen.ActiveForm.Name
![recordid] = Screen.ActiveForm.Controls(IDField).Value
![FieldName] = ctl.ControlSource
![beforeValue] = beforeValue
![afterValue] = afterValue
.Update
End With
End If
End If
Next ctl
Когда ctl
ссылается на многозначное поле со списком, в котором выбран хотя бы один элемент, ваше условие проверки...
Nz(ctl.Value) <> Nz(ctl.OldValue)
... безусловно, выдаст ошибку несоответствия типов. В этой ситуации ctl.Value
на самом деле вариантный массив, и Nz()
не могу справиться с этим. Проблема, по сути, такая же, как эта...
Debug.Print Nz(Array(1,2,3)) '<- type mismatch error
Возможно, вы бы предпочли захватить строку конкатенированных комбинированных выделений...
Debug.Print Join(ctl.Value, ",")
Если это кажется полезным, будьте осторожны, что ctl.Value
будет нулевым, если ни один из его элементов не выбран. И пытается Join()
Null также вызовет ошибку несоответствия типов.
Обратите внимание, что эти вопросы также относятся к ctl.OldValue
,
Но может быть еще одно осложнение. На основании моих испытаний я скептически OldValue
является надежным для многозначного поля со списком. Если вы также обнаружите, что это так, используйте текущее событие формы, чтобы сохранить начальные выборы комбо в переменной уровня формы и ссылаться на эту переменную (вместо OldValue
) в вашей процедуре аудита.