GrialApl, Transacción Visual
De GrialWIKI
Contenido |
Control Principal: GrialCont / GrialApl
El Control GrialCont representa visualmente una transacción, estandarizando el flujo del programa en todos los módulos del sistema. Adicionalmente brinda el servicio de seguridad, conexión y acceso a los controles registrados.
Control GrialCont:

El control determina un flujo de programa estandarizado:

Codificación Estándar: Inicialización, Centrado y Finalización
Componentes Adicionales Requeridos
Dentro de cada GrialCont debe colocarse un objeto "Frame" de VB con el nombre [Container_Frm], dicho frame contendrá todos los controles de edición involucrados en la transacción.
Al iniciarse una transacción, se hace visible el frame "Container_Frm" (y se dispara el evento ContainerFrmShow), permitiendo la operación del usuario.
Al finalizar la transacción, se oculta dicho frame (y se dispara el evento ContainerFrmHide).
Si al iniciar una transacción, durante el evento ButtonClick, se establece el estado de sólo visualización (NewState=VIEW_MODE), se mostrará el Container_Frm pero deshabilitado.
En caso de tener más de un objeto GrialCont dentro de un mismo módulo, debe crearse un Container_Frm para cada uno, generando así un array de frames Container_Frm(0..n), uno dentro de cada uno de los objetos GrialCont.
Método Initialize
Se debe invocar el método GrialCont.Initialize en el evento UserDocument_Show (primer evento una vez mostrada la pantalla del módulo).
Formato:
Sub GrialCont.Initialize ( UserDocument_Name As String, Parent_LocationURL As String )
El método Initialize:
- Establece los accesos de seguridad según el usuario
- Prepara la conexión para el acceso a datos
- Prepara la configuración de los controles registrados
En el mismo momento, se deben dejar visibles sólo aquellos botones de la barra superior contemplados en el código.
Ejemplo:
Private Sub UserDocument_Show ( . . . With GrialCont .Initialize UserDocument.Name, Parent.LocationUrl .CheckVersion App .TopBar_AllButtonsVisible False ' Todos invisibles 'Habilito sólo Alta, Baja y Modificación .ButtonStd_Visible BUTTON_MODIFICATION, True .ButtonStd_Visible BUTTON_NEW, True .ButtonStd_Visible BUTTON_DELETE, True End With
También es posible cambiar la descripción de cualquiera de los botones.
Ejemplo:
.ButtonStd_Caption BUTTON_MODIFICATION, "Seleccionar" .ButtonStd_Caption BUTTON_CANCEL, "Cerrar"
Método Center
Se debe invocar este método en el evento UserDocument_Resize para centrar el objeto que contenga al resto de los objetos dentro de la pantalla.
Formato:
Sub GrialCont.Center ( xViewportWidth As Integer, GeneralContainer As Object )
Ejemplo:
GrialCont.Center ViewportWidth, General_GFF GrialCont.Center ViewportWidth, TabGeneral
En el parámetro [GeneralContainer As Object] se indica el objeto que contiene al resto de los objetos de la función, por ejemplo cuando la aplicación presenta inicialmente varios tabs con un contenedor distinto en cada uno de ellos, será el objeto "Tab" el que contenga toda la aplicación.
Método Finalize
Debe ser invocado en el evento UserDocument_Hide (último evento antes de cerrar el formulario). Realiza descargas de los objetos cargados. Su ausencia puede provocar fallas en la salida del módulo.
Formato:
Sub GrialCont.Finalize()
Ejemplo:
Sub UserDocument_Hide GrialCont.Finalize End Sub
El método Finalize desconecta los controles registrados para evitar errores de protección general (GPF) en el cierre del documento.
Flujo de Programas, de ButtonClick a BottomButtonClick
El flujo del programa estará determinado por los controles GrialApl incluidos en el módulo.
Se presenta a continuación un ejemplo de construcción y codificación de una transacción modelo dentro de un contenedor (GrialApl).
La transacción modelo consiste de un GrialCombo de selección colocado sobre la barra superior de un control GrialApl. Dentro de la zona de edición se colocan los controles necesarios para modificar el conjunto de datos representado por el combo.
Variables Globales
Se crean variables globales para almacenar: el ID actual en edición (por ejemplo: "IDPreEjec20", para llevar los contadores de falsos ID's para las tablas de detalles (Por Ejemplo: "Falso_IDPreEjec21") y objetos GrialQuery como espacio de memoria para editar los regsitros (recordsets troncales)
Ejemplo:
Dim IDPreEjec20 as Long Dim PreEjec20_grq as New GrialQuery Dim Falso_IDPreEjec21 as Long Dim PreEjec21_grq as New GrialQuery
Inicio de la Transacción
Evento ButtonClick
El evento ButtonClick determina el inicio de la transacción. En base al botón pulsado por el usuario (Alta, Baja, Modificación, etc.) se prepararán los datos correspondientes para la transacción.
Formato:
Event ButtonClick ( GrialButtonCode As GrialButtons, Cancel As Integer , NewState As Operation_States )
El usuario selecciona el registro sobre el cual desea operar en el combo, y luego pulsa uno de los botones de la barra superior (Alta, Modificación o Baja) lo que dispara un evento GrialCont_ButtonClick. En este evento se debe verificar que el usuario haya seleccionado correctamente un registro (para los casos de Modificación y Baja) y luego invocar un procedimiento para preparar la transacción (Sub PrepararTransaccion)
La variable global con el ID en edición se cargará al momento del evento GrialCont_ButtonClick con el ID del registro seleccionado en el combo (propiedad CurrentValue del combo). En caso de Alta de un nuevo registro, se utilizará el valor -1 como ID.
Private Sub GrialCont_ButtonClick(ByVal GrialButtonCode As GrialApp.GrialButtons, Cancel As Integer, NewState As GrialApp.Operation_States) On Error GoTo ErrH Select Case GrialButtonCode Case BUTTON_NEW PreEjec20_scb.PrepareAddNew 'Abro un espacio nuevo en el Combo de seleccion IDPreEjec20 = -1 PrepararTransaccion Case BUTTON_MODIFICATION,BUTTON_DELETE If NoDataIn(PreEjec20_scb.CurrentValue) Then Err.Raise 5,,"Debe elegir un registro" IDPreEjec20 = ID_PreEjec20_scb.CurrentValue PrepararTransaccion Case Else 'boton no implementado Cancel = True End Select Exit Sub ' ------ Manejo de errores ErrH: MsgError GrialCont ' Le muestro el error al usuario Cancel = True ' Cancelo el evento, la pantalla permanecerá igual ' y el usuario podrá reintentar la operación End Sub
Preparar Transaccion
El procedimiento "PrepararTransaccion" debe recuperar de la BD un recordset para cada tabla troncal afectada en la transacción. Se cargará un objeto GrialQuery con cada uno de los recordsets troncales necesarios para la transacción. En la condición "where" del recupero de datos se utilizará la variable global con el ID en edición.
Private Sub PrepararTransaccion() PreEjec20_grq.Init "select * from sic_docu_01 where ID_PREEJEC20=" & IDPreEjec20 PreEjec21_grq.Init "select * from sic_docu_02 where RELA_PREEJEC20=" & IDPreEjec20 PreEjec21_scb.ExtraFilterCondition = "RELA_PREEJEC20=" & IDPreEjec20 'Grilla Detalle Grial_Cont.LoadData PreEjec20_grq, PreEjec21_grq, PreEjec21_scb If IDPreEjec20 = -1 Then ' Alta PreEjec20_grq.PrepareAddNew 'Recordset Troncal en memoria With PreEjec20_grq.Rst !ID_PREEJEC20 = -1 'Datos que solo se asignan en un Alta !PREEJEC20_FAPL = Now End With End If PonerEnPantalla 'Pongo troncal y detalle en pantalla End Sub
Explicación del caso de Alta (ID=-1, nuevo registro):
Al ser el valor del ID = –1, el resultado del select será vacío (ya que la condición será: Where ID_PREEJEC20 = -1), por lo tanto dentro del procedimiento PrepararTransaccion se debe invocar el método PrepareAddNew para el GrialQuery de tabla troncal.
El método PrepareAddNew genera un registro nuevo en el recordset en memoria, creando un espacio en el recordset donde el módulo puede trabajar. Todos los campos son inicializados con el valor NULL, por lo que al mostrar los datos en pantalla, se mostraran todos los datos en blanco.
Luego de preparar el nuevo registro se deberá dar valor a los campos que sólo son cargados en el alta, es decir, aquellos que permanecen inalterables durante toda la existencia del registro. Por lo general estos campos son el ID del registro, la fecha de Alta y los campos RELA a la cabecera (en las tablas de detalle).
Es recomendable realizar la carga de los campos que permanecen inalterables durante toda la existencia del registro en este punto en el cual se "crea" el registro. NO es recomendable hacerlo al momento de aceptar la transacción, ya que por error de programa, se podría modificar el campo ID o el campo FAPL (Fecha de Alta) de un registro antiguo.
Al final del procedimiento PrepararTransaccion tendremos los espacios necesarios en memoria (en los recordsets troncales) para que el usuario pueda operar dentro de la transacción. Tendremos la información completa del registro recuperado o un nuevo registro en blanco para el caso de alta.
En este momento invocaremos un procedimiento para volcar los datos desde el espacio de memoria (registros en los recordsets troncales) hacia los controles de edición en la pantalla. Por norma lo llamaremos PonerEnPantalla.
Private Sub PonerEnPantalla() With PreEjec20_grq.Rst AssignTextField PreEjec20_Descri_txt, !PREEJEC20_DESCRI AssignTextField PreEjec20_Cod_txt, !PREEJEC20_COD SysWflo06_scb.CurrentValue =!RELA_SYSWFLO06 Fapl_Lb = FormatDate(!PREEJEC20_FAPL ) End With End Sub
En este procedimiento se usarán la rutinas AssignTextField para volcar datos a controles de texto y FormatDate para volcar datos de tipo fecha en Labels. Por norma, los controles de tipo Textbox que se utilizan para editar campos de la base, deben tener el mismo nombre del campo con el sufijo _txt adicionado, por ejemplo PreEjec20_Descri_txt
Una vez mostrados los datos, el usuario podrá operar con la pantalla de la transacción, hasta que pulse alguno de los botones de la barra inferior (Aceptar o Cancelar) disparándose entonces el evento GrialCont_BottomButtonClick
Evento ContainerFrmShow
El evento ContainerFrmShow sucede posteriormente al inicio de la transacción (Evento ButtonClick) y antes de hacer visibles los controles dentro del GrialCont. Debe utilizarse para realizar ajustes en la pantalla según los datos recuperados de la transacción y habilitar o deshabilitar controles. El evento ContainerFrmShow se ejecuta si y sólo si se ha iniciado satisfactoriamente la transacción, y se está por mostrar la pantalla (es decir, si se recuperaron correctamente los datos desde la base y NO se salió con cancel=true del evento ButtonClick).
El parámetro NewState informa estado elegido durante el evento ButtonClick. Por default toma el valor CONTROLS_ENABLED para el botón de Alta y Modificación y el valor VIEW_MODE (todos los controles deshabilitados) para el botón de Baja.
Dentro de este procedimiento debe deshabilitarse el combo superior, para que el usuario no pueda cambiar el registro elegido mientras está dentro de la transacción.
Formato:
Event ContainerFrmShow (NewState As Operation_States)
Ejemplo:
Private Sub GrialCont_ContainerFrmShow (NewState As Operation_States) PreEjec20_scb.Enabled = False End sub
Operación del Usuario
Mientras se encuentre habilitado el GrialCont, el usuario podrá operar con los controles de la pantalla. Los botones superiores del GrialCont se deshabilitan automáticamente y se habilitan los botones inferiores, permitiendo al usuario dos opciones: ACEPTAR o CANCELAR.
Cierre de la Transacción
El evento BottomButtonClick determina la finalización de la transacción. Se dispara cuando el usuario hace click en uno de los botones de la barra inferior (ACEPTAR o CANCELAR). Dependiendo de la acción elegida (BUTTON_ACCEPT o BUTTON_CANCEL) se validarán y aceptarán los datos o se cancelará completamente la transacción. En caso que el usuario haya pulsado el botón ACEPTAR se procederá a la validación de los datos ingresados y a su transferencia hacia los recordsets troncales en memoria. La validación y la transferencia de los datos en pantalla hacia los espacios de memoria en el recordset troncal se realizan en un procedimiento que llamaremos TomarDatosdePantalla.
Procedimiento TomarDatosdePantalla
Dentro de este procedimiento usaremos:
- Para los campos individuales, la rutina UpdateField y UpdateFieldNum que permiten actualizar un campo de un recordset y validar por contenido nulo en la misma operación.
- Para recuperar datos de una Grilla editable en pantalla, el procedimiento Grid_UpdateUserInput (para cerrar el modo edición) y luego ChangeMainRst para actualizar el recordset troncal desde los registros de la grilla en pantalla.
Private Sub TomarDatosdePantalla() With PreEjec20_grq.Rst If ValCur(PreEjec20_Porcentaje_Txt) > 100 then Err.Raise 5,,"El Porcentaje debe ser menor que 100" End if UpdateField !PREEJEC20_PORCENTAJE, valcur(PreEjec20_Porcentaje_Txt) UpdateField !PREEJEC20_DESCRI, PreEjec20_Descri_txt, "una descripción" UpdateField !RELA_SYSWFLO06, SysWflo06_scb.CurrentValue End With ' Aplico los cambios realizados por el usuario en la grilla en el recordset troncal PreEjec21_Scb.Grid_UpdateUserInput GrialCont.ChangeMainRst PreEjec21_qrq.Rst, PreEjec21_Scb.Rst, "ID_PREEJEC21" End Sub
(Nota: Todas las validaciones deben realizarse dentro este procedimiento y sólo si el usuario pulsa el botón "Aceptar". NO deben realizarse validaciones en eventos del tipo "_LostFocus" o "_Change").
Evento BottomButtonClick
En el evento GrialCont_BottomButtonClick creamos un objeto del tipo GrialTransaction para preparar la transacción que enviaremos al servidor.
Ejemplo:
Private Sub GrialCont_BottomButtonClick(ByVal GrialButtonCode As GrialApp.GrialButtons _ , Cancel As Integer, NewState As GrialApp.Operation_States) On Error GoTo ErrH Dim Txn As New GrialTransaction Select Case GrialButtonCode Case BUTTON_ACCEPT Select Case GrialCont.LastButton Case BUTTON_NEW, BUTTON_MODIFICATION 'Validación y toma de datos TomarDatosdePantalla 'Preparo la transaccion Txn.Add PreEjec20_Grq,"ID_PREEJEC20" ' Cabecera Txn.Add PreEjec21_Grq,";RELA_PREEJEC20" ' Detalle 'Aplico la transacción en el servidor GrialCont.Apply Txn If GrialCont.LastButton = BUTTON_NEW then IDPreEjec20 = Txn.NewIDValue 'Recupero el nuevo ID creado End If; ' Refresco los cambios en el combo superior PreEjec20_scb.LoadOnCurrentRecord IDPreEjec20 ' Refresco el registro del combo Case BUTTON_DELETE PreEjec20_Grq.DeleteRecord PreEjec21_Grq.DeleteAllRecords 'Preparo la transaccion Txn.Add PreEjec20_Grq.Rst ' Cabecera Txn.Add PreEjec21_Grq.Rst ' Detalle 'Aplico la transacción en el servidor GrialCont.Apply Txn PreEjec20_scb.DeleteRecord 'Elimino registro del combo superior End Select Case BUTTON_CANCEL Select Case GrialCont.LastButton Case BUTTON_NEW PreEjec20_scb.CancelAddNew 'deshago el alta en el combo superior End Select End Select End If Exit Sub ' ------ Manejo de errores ErrH: MsgError GrialCont 'Le muestro el error al usuario If Txn.Commited then resume Next ' Si ya commiteo, ignoro el error Cancel = True 'Cancelo el evento de cierre de la pantalla 'Al cancelar el BottomButtonClick, la pantalla permanecerá igual, 'y el usuario podrá reintentar la operación End Sub
Descripción de la operatoria
Luego de recuperar los datos de pantalla, se confecciona la transacción dentro de un objeto GrianTransaction mediante el método Add. Tanto para el Alta de registros como para Modificación, la transacción armada y enviada al servidor es la misma. Los registros deben enviarse en orden, primero los registros de cabecera y luego los registros de detalle y se debe indicar la relación entre los mismos (que campo es ID y qué campo es RELA)
Para el caso de Baja, se eliminarán los registros correspondientes de los recordsets troncales y se envían los recordsets al servidor. Los registros deben enviarse en orden, primero los registros de cabecera y luego los registros de detall, pero no es necesario para la eliminación física de registros especificar la información campos ID y RELA.
La baja física debe utilizarse en caso de excepción. Los controles de FK (Foreign Keys) en la base de Datos evitan que se elimine físicamente un registro si es referenciado desde otra tabla. Este control es realizado automáticamente por la BD.
Si se desea realizar una baja lógica o anulación, debe permitirse al usuario marcar/desmarcar un checkbox de fecha de baja y actualizar el campo de Fecha de Baja Lógica correspondiente en el registro. Un registro dado de baja lógica no podrá ser utilizado para relacionarlo desde otras tablas, pero sí debe aparecer en el combo de selección del módulo principal de la tabla, para permitir su recuperación (desmarcando el checkbox de Fecha de Baja).
Debe tomarse en cuenta que en caso de error, el usuario podrá reintentar la transacción (al salir con Cancel=True, no se cierra la transacción visual), por lo que debe verificarse que el código para BUTTON_ACCPET pueda ser ejecutado más de una vez en caso de reintentos.
Evento ContainerFrmHide
El evento ContainerFrmHide se dispara una vez cerrada la transacción (Luego del evento BottomButtonClick). Debe utilizarse para rehabilitar los controles deshabilitados el inicio de la edición (como un espejo del evento ContainerFrmShow).
Ejemplo:
Private Sub GrialCont_ContainerFrmHide(ByVal ActualState As GrialApp.Operation_States) PreEjec20_scb.Enabled = True End sub
Nota:
No se deben realizarse cargas de datos (LoadData) en el evento ContainerFrmHide. Esto es debido a que el evento ContainerFrmHide se ejecuta una vez al comienzo del modulo (durante el GrialCont.Initialize) y en ese momento no está preparada aún la conexión de datos.