Parece que has caído en algunos de los escollos comunes, pero no te preocupes, se pueden solucionar :)
Primero debe ver su aplicación de manera un poco diferente y comenzar a dividirla en trozos. Podemos dividir los trozos en dos direcciones. Primero podemos separar la lógica de control (las reglas de negocio, el código de acceso a datos, el código de derechos de usuario, todo ese tipo de cosas) del código de la interfaz de usuario. En segundo lugar, podemos dividir el código de la interfaz de usuario en fragmentos.
Entonces haremos la última parte primero, dividiendo la IU en trozos. La forma más fácil de hacer esto es tener un único formulario de host en el que compones tu interfaz de usuario con controles de usuario. Cada control de usuario estará a cargo de una región del formulario. Imagine que su aplicación tiene una lista de usuarios, y cuando hace clic en un usuario, un cuadro de texto debajo se llena con sus detalles. Puede tener un control de usuario que administre la visualización de la lista de usuarios y un segundo que administre la visualización de los detalles del usuario.
El verdadero truco aquí es cómo gestionar la comunicación entre los controles. No querrá 30 controles de usuario en el formulario, todos con referencias aleatorias entre sí y métodos de llamada.
Entonces creas una interfaz para cada control. La interfaz contiene las operaciones que el control aceptará y cualquier evento que genere. Cuando piensa en esta aplicación, no le importa si cambia la selección de la lista del cuadro de lista, le interesa el hecho de que un nuevo usuario haya cambiado.
Entonces, utilizando nuestra aplicación de ejemplo, la primera interfaz para el control que aloja el cuadro de lista de usuarios incluiría un evento llamado UserChanged que pasa un objeto de usuario.
Esto es genial porque ahora si te aburres del cuadro de lista y quieres un control de ojo mágico con zoom 3d, simplemente codifícalo en la misma interfaz y conéctalo :)
Ok, entonces la segunda parte, separando la lógica de la interfaz de usuario de la lógica del dominio. Bueno, este es un camino muy usado y te recomiendo que mires el patrón MVP aquí. Es muy simple
Cada control ahora se llama Vista (V en MVP) y ya hemos cubierto la mayor parte de lo que se necesita arriba. En este caso, el control y una interfaz para ello.
Todo lo que estamos agregando es el modelo y el presentador.
El modelo contiene la lógica que gestiona el estado de su aplicación. Ya sabes las cosas, iría a la base de datos para obtener los usuarios, escribir en la base de datos cuando agregas un usuario, y así sucesivamente. La idea es que puede probar todo esto en completo aislamiento de todo lo demás.
El presentador es un poco más complicado de explicar. Es una clase que se encuentra entre el modelo y la Vista. Es creado por la vista y la vista pasa al presentador usando la interfaz que discutimos anteriormente.
El presentador no tiene que tener su propia interfaz, pero me gusta crear una de todos modos. Hace que lo que quieres que haga el presentador sea explícito.
Por lo tanto, el presentador expondría métodos como ListOfAllUsers que la Vista usaría para obtener su lista de usuarios, alternativamente, podría colocar un método AddUser en la Vista y llamarlo desde el presentador. Prefiero el último. De esta forma, el presentador puede agregar un usuario al cuadro de lista cuando lo desee.
El presentador también tendría propiedades como CanEditUser, que devolverá verdadero si el usuario seleccionado se puede editar. La Vista consultará eso cada vez que necesite saber. Es posible que desee los editables en negro y los de solo lectura en gris. Técnicamente, esa es una decisión para la Vista, ya que está enfocada en la IU, si el usuario es editable en primer lugar es para el Presentador. El presentador sabe porque habla con el modelo.
En resumen, use MVP. Microsoft proporciona algo llamado SCSF (Smart Client Software Factory) que usa MVP de la manera que he descrito. Hace muchas otras cosas también. Es bastante complejo y no me gusta cómo lo hacen todo, pero puede ayudar.