programar - Desde la forma principal, ejecute VBA para validar total en subformulario
vba access pdf (2)
Me saltaría usar la interfaz de usuario por completo y mirar las tablas. Si esto se ejecuta en un botón de comando de formulario principal, el subformulario ha perdido el foco y ha guardado sus valores. Una nueva consulta es innecesaria. Simplemente recree la relación Padre-Hijo en el criterio (tercer parámetro) de un DSum:
If DSum("QtyToShip", "ShipmentDetails", "ShipmentID = " & Me!ShipmentID) <= 0 Then
MsgBox "Cannot create shipment, no quantities have been entered", vbCritical
Exit Sub
End If
Tengo un formulario en MS Access 2002 con el siguiente fragmento de código detrás de un botón de comando.
''Requery subform to make sure total is calculated
Me.fsubUpdateShipments.Requery
DoEvents
''Confirm quantities have been entered
If Form_fsubUpdateShipments.txtTotalShipmentQty.Value <= 0 Then
MsgBox "Cannot create shipment, no quantities have been entered", vbCritical
Exit Sub
End If
Durante meses, esto ha funcionado bien, pero hoy un colega vino a mí y me explicó que el mensaje de error aparecía incluso cuando habían ingresado cantidades.
Después de investigar un poco, determiné que la .Value <= 0
estaba siendo evaluada antes de que el cuadro de texto en cuestión terminara de calcular su valor: =Sum([QtyToShip])
. Esto parece ocurrir solo cuando el subformulario tiene una cantidad no trivial de registros (alrededor de 10 o más) y obviamente es un problema grave.
Agregar un punto de interrupción en la línea que contiene la instrucción If
permite que el código se ejecute correctamente, pero obviamente no puedo usar este método permanentemente.
¿Hay alguna manera de forzar al código a pausar hasta que los controles del subformulario hayan terminado de recalcular sus valores?
Hay dos opciones, ambas ya identificadas por otros, pero como sus sugerencias son incompletas o desordenadas (lentas), estoy haciendo esta publicación.
R. Podría poner una espera forzada para retrasar la prueba IF:
Pon esto en un módulo:
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
...
Public Sub GoSleep(millisecondDelay as long)
Sleep (millisecondDelay)
End Sub
Y en tu forma:
''Requery subform to make sure total is calculated
Me.fsubUpdateShipments.Requery
DoEvents
GoSleep 1000 ''1 second delay. Or 2000, whatever is required really
''Confirm quantities have been entered
If Form_fsubUpdateShipments.txtTotalShipmentQty.Value <= 0 Then
MsgBox "Cannot create shipment, no quantities have been entered", vbCritical
Exit Sub
End If
B. Como dice otra respuesta, puede recalcularlo usted mismo y evaluarlo en función de este resultado.
Sin embargo, en lugar de usar DSum como sugiere pteranodon, sugeriría algo más rápido que DSum, ya que DSum (DCount, etc.) es muy lento.
Normalmente utilizo ADO para operaciones de datos, aunque mi código se puede adaptar para DAO con la suficiente rapidez. Para usar este código necesitarás una referencia a Microsoft activeX 2.8 si aún no tienes uno:
En un módulo:
Public Function GetDBValue(qry as string) as variant
dim rst as new adodb.recordset
rst.open qry, currentproject.connection, adOpenKeyset, adLockReadOnly
if rst.eof then
GetValue = null
else
GetValue = rst.fields(0)
end if
end function
public Function IsNullSQL(basevalue as variant, replacementvalue as variant) as variant
isNullSQL = iif(isnull(basevalue), replacementvalue, basevalue)
end function
en tu forma:
''''Requery subform to make sure total is calculated
''Me.fsubUpdateShipments.Requery
''DoEvents
''Confirm quantities have been entered
If IsNullSQL(GetValue("SELECT Sum(QtyToShip) FROM tbl WHERE ..."), -1) < 0 Then
MsgBox "Cannot create shipment, no quantities have been entered.", vbCritical, "No Quantities to Ship"
Exit Sub
End If
''If Form_fsubUpdateShipments.txtTotalShipmentQty.Value <= 0 Then
'' MsgBox "Cannot create shipment, no quantities have been entered", vbCritical
'' Exit Sub
''End If