refactoring - MS Access: la mejor forma de modularizar/desacoplar formularios para refactorizar
access-vba modularity (2)
Así que he estado trabajando recientemente con una gran base de datos de acceso y he estado pensando en la mejor manera de empezar a refactorizarla. Una de las principales dificultades en la refactorización es que la mayoría de las formas se basan en datos de otras formas.
La forma en que se hace actualmente es así;
Form1
tiene un botón denominado Cmd1
que abre un formulario nuevo ( DoCmd.OpenForm "Form2"
) y rellena algunos controles en el formulario utilizando Forms!Form2.Control = Me.Control
. Al cerrar Form2
, los datos se devuelven a Form1
llamando a Forms!Form1.Control = Me.Control
.
Esto presenta un problema si deseo cambiar los nombres de cualquiera de los formularios, o qué formulario abre el formulario emergente. También requiere que ambos formularios estén abiertos, en lo que realmente no puede confiar cuando no puede usar formularios emergentes modales porque los usuarios desean poder intercambiar entre formularios.
Veo 5 métodos para pasar valores entre formularios, cada uno con sus problemas, y me preguntaba qué se recomendaba.
- El método ya está en su lugar como se explicó anteriormente.
- Usar OpenArgs: hace que muchos valores sean difíciles ya que tiene que analizar una cadena y es unidireccional.
- Usar variables globales: esto significaría toneladas de variables en un módulo aleatorio y presenta una pesadilla de alcance.
- Almacenamiento de valores para pasar entre formularios en una tabla temporal.
Mantener una referencia a la primera forma usando
Public master As Form Private Sub Form_Load() Set master = Screen.ActiveForm Me.Control = master.Control End Sub
Lo cual es bueno, ya que puede hacer referencia a formularios de abuelos como
master.master.control
pero podría causar algunos problemas importantes si un control en un formulario principal desaparece en el futuro.
Entonces, sí, ¿hay un método recomendado?
Esta es una pregunta tan crítica para desarrollar una aplicación de acceso profesional y mantenible.
Primero, algunos comentarios en su lista de métodos:
- Estoy de acuerdo con su evaluación de los inconvenientes de los métodos # 1 y # 2
- Los números 3 y 4 comparten el mismo problema: una tabla global es tan global como una variable global. No se puede limitar fundamentalmente el acceso a cualquiera de ellos.
- # 5 inevitablemente te meterá en problemas. La referencia extra a largo plazo al formulario evitará, en ciertas circunstancias, que se cierre.
Yo propondría mover toda su lógica comercial en módulos separados, desglosados por formulario. Esto le permite evitar los problemas globales con los números 3 y 4, porque los módulos pueden tener funciones y variables privadas a nivel de módulo.
Por ejemplo, un formulario llamado frmFoo
obtendría un módulo coincidente llamado modFrmFoo
. El módulo contendría todos los métodos públicos para usar frmFoo:
Aquí hay un modFrmFoo simplificado:
Private mvID As Variant
'' read-only (no Let)
Public Property Get frmFoo_ID() As Variant
frmFoo_ID = mvID
End Property
Public Sub frmFoo_Show(ID As Variant, Name As Variant)
'' note use of temporary object reference
Dim rFoo As Form_frmFoo
mvID = ID
DoCmd.Open acForm, "frmFoo"
Set rFoo = Forms("frmFoo")
rFoo.ShowName Name
End Sub
El módulo de formulario frmFoo necesita un método público:
'' only frmFoo should refer to its internal controls and code
Public Sub ShowName(Name As Variant)
lblName.Caption = Name
End Sub
Y, la consulta para frmFoo:
SELECT ID, [other stuff] FROM tblFoo WHERE tblFoo.ID = frmFoo_ID()
La consulta sincroniza los resultados con el valor ID devuelto por la propiedad frmFoo_ID ().
Mostrar frmFoo desde otra forma es fácil:
'' frmBar
Private Sub cmdShowFoo_Click()
frmFoo_Show 123, "your name"
End Sub
Ventajas de este método:
- Define una interfaz pública para todas las operaciones públicas en un formulario. Los formularios externos llaman al módulo, nunca el formulario directamente.
- Mantiene privada la actividad privada de todos los formularios: los controles de formulario se pueden renombrar o eliminar sin alterar el resto de formularios que dependen de él.
- Define en una llamada lo que se necesita para que funcione cada método; por ejemplo, frmFoo_Show () requiere ID y Nombre.
Esto se corresponde con la forma en que haría una nueva aplicación desde cero.
Si es práctico para actualizar una aplicación vieja y enredada es su llamado.
Esto podría ser de ayuda:
Puede abrir formularios y controlarlos sin utilizar Open Args
Para ello, abra otro formulario como si fuera una clase
Cree un módulo llamado GlobalVars que incluya esta línea:
Public Form_MyFormNameToOpen as Form_MyFormNameToOpen
(El formulario que abra permanecerá abierto hasta que esta variable "muera", por lo tanto, hágalo global para mantenerlo vivo)
MyFormNameToOpen es el nombre del formulario que desea abrir y tiene Form_ delante de él en algunos de mis códigos de ejemplo. Esto le dice a access que obtenga una "clase de formulario", es decir, una de las formas que creó.
Luego, en el código que desea abrir un formulario, use:
'' Opens the form using it as it were a class
Set GlobalVars.Form_MyFormNameToOpen = New Form_MyFormNameToOpen
'' The modify the form you have just opened however you want to.
With Form_MyFormNameToOpen
.Visible = True
'' This relies ont he control names never changing
.Controls("ProviderID") = 10
.Controls("ProviderFileID") = 11
'' it''s better to use properties created on the called form
'' eg
.MyLetProviderID = 10
.MyProviderFileID = 11
End With
Espero que esto ayude.
Encuentro que usar args abiertos es un verdadero dolor, excepto por las cosas más básicas. Usar formularios como este hace la vida mucho más fácil.
(quizás pueda usar una técnica similar para informes, subformularios, etc.)