这里有一个完整的解决方案,可以正确地处理新编辑的记录,并处理访问用户界面的问题(即,重新绘制失败、不一致的行为取决于如何选择记录——通过鼠标或键盘或记录选择器等)。我包含冗长的注释,因为access需要彻底的解释,因为它有许多不一致和/或错误。我尝试过更精简的解决方案,但如果没有强制访问以重新绘制表单的技巧,或者没有在detail_paint()事件处理程序中确定当前记录的复杂方法,那么它的性能肯定不好。
该代码用于带有绑定到id autonumber字段的文本框的访问表单。表单还有一个名为boxcurrent的矩形控件,该控件将被更新以突出显示当前选定的记录(它有一个明亮的宽边框)。我发现矩形控件提供了比设置detail.backcolor更多的视觉选项,尽管这些细节可以使用总体模式公开配置。使用Access 2013和2016进行开发和测试。
'* Set this value in From_Current event handler
Private vCurrentAutonumber As Variant
Private Sub Detail_Paint()
'* Delcare static variables to make often repeated calls more efficient.
Static iActive As Integer
Static vThisValue As Variant, vOldValue As Variant
On Error Resume Next
iActive = 0 '* Default to False/hidden value
vThisValue = Me.ID.Value
If Err.Number = 0 Then
If Not IsNull(vCurrentAutonumber) Then
If vThisValue = vCurrentAutonumber Then iActive = 1
ElseIf Me.NewRecord Then
'* Form currently set to "New Record", but may or may not be in edit mode.
'* When in EDIT MODE, AutonumberControl.Value will HAVE A VALUE
' AND AutonumberControl.OldValue will be null
' When NOT in edit mode, AutonumberControl.Value will be null
' AND AutonumberControl.OldValue will also be null
'*** That is the only way I have found to determine for sure
' if the currently-edited-new-record is the available record for
' this particular call of Detail_Paint().
' Other properties like CurrentRecord, NewRecord, etc. remain
' unchanged during repeated calls to Detail_Paint()
' and access has no other convenient way to determine the
' newly-added autonumber value, so it must be deduced using
' this trick.
If IsNull(vThisValue) Then
If Not Me.Dirty Then
'Record selector on *(New Record) row, but not edited yet.
If Err.Number = 0 Then iActive = 1
End If
Else
vOldValue = Me.ID.OldValue
If Err.Number = 0 Then
If IsNull(vOldValue) Then
'* Newly-edited record with fresh autonumber value is selected.
iActive = 1
'Else if vOldValue is not null, it is an existing record.
'* Not the current record since it can't be both existing and new.
End If
End If
End If
End If
End If
'* Set these values on EACH CALL, since their values will be retained
'* on subsequent calls.
With boxCurrent
.BackStyle = 0 'iActive
.BorderStyle = iActive
End With
End Sub
Private Sub Form_AfterDelConfirm(Status As Integer)
Me.Repaint
End Sub
Private Sub Form_AfterInsert()
If IsNull(vCurrentAutonumber) Then
'* If a new record is saved while staying on that record,
'* the Form_Current() handler is not called and so the
'* vCurrentAutonumber would not be updated with the newly
'* saved value. But now Me.NewRecord is false, so the
'* currently record would not be updated properly unless
'* vCurrentAutonumber is explicitly updated here.
On Error Resume Next
vCurrentAutonumber = Me.ID.Value
'* Force repaint (see comment in Form_Current)
boxCurrent.BackColor = vbBlue
End If
End Sub
'Private Sub Form_BeforeInsert(Cancel As Integer)
'* Attempted to set some variable or property in this event handler
'* --something to indicate to Detail_Paint() which record is the
'* new record being edited. But no matter what I set here, the
'* change is present and identical for each call of Detail_Paint(),
'* so for the most part this technique was not useful.
'* The only alternative is to set one of the data fields, because
'* those DO change for each each to Detail_Paint().
'* IF THE PRIMARY KEY IS NOT AN AUTONUMBER FIELD (OR IF ANOTHER
'* DATA FIELD IS AVAILABLE TO MANIPULATE), ONE COULD FLAG A NEWLY
'* EDITED RECORD BY SETTING SUCH A FIELD HERE AND INSPECTING
'* it in Detail_Paint(). Personally, I avoid dummy fields just for
'* making Access work well and my primary key is Autonumber so it cannot
'* bet set to a known new value.
'End Sub
Private Sub Form_Current()
On Error Resume Next
vCurrentAutonumber = Me.ID.Value
If Err.Number <> 0 Then vCurrentAutonumber = Null
On Error GoTo 0
'*** FORCE REPAINT of record detail section
'* If not forced, records are not necessarily repainted for every type of
'* UI event. For instance, changing records using the record selectors
'* has different behavior than clicking inside a record, but either way
'* the current record has changed and so should be repainted.
'* But calling Me.Repaint is not sufficient to actually repaint the form.
'* Even if the Detail_Paint event is called, the actual visible elements
'* are not always repainted (bug?). It seems that only changing some
'* visible feature/control of the form will force an actual repaint.
boxCurrent.BackColor = vbBlue
End Sub
Private Sub Form_Load()
vCurrentAutonumber = Null
End Sub