You are on page 1of 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

Manejo de Formularios MDI con C#


Antes de iniciar debemos aclarar que existen dos tipos de Formularios:
SDI (Single Document Interface)
MDI (Multiple Document Interface)
Los Formularios MDI son aquellos que permiten contener otros formularios dentro de ellos.
Para crear una aplicacin de tipo MDI primeramente tenemos que crear nuestro proyecto
(Aplicacin de Windows).
En el formulario principal debemos establecer la propiedad IsMdiContainer a True.

Formulario Principal

Posteriormente debemos Crear el formulario base que ser la plantilla que tendrn nuestros
formularios child. En nuestro caso hemos tratado de simular un editor de texto bastante simple
pero con soporte MDI.
Agregamos un nuevo formulario a nuestro proyecto.
Agregamos un primer panel en la parte inferior que podr contener botones si as lo deseamos,
para hacer eso establecemos la propiedad Dock del panel en Bottom.

Despus agregamos un segundo panel que contendr nuestro cuadro de texto y establecemos la
propiedad Dock en Fill.

P g i n a 1 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

Agregamos nuestro textbox y lo renombramos a txtBoxContent y establecemos su


propiedad Dock en Fill.

Agregamos un botn al panel de la parte inferior que sera la simulacin de un botn que servir
para guardar nuestro documento. Con esto tendremos nuestro formulario base.

P g i n a 2 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

Formulario Base

Ahora crearemos un men para tener una administracin muy sencilla de las ventanas child (en
el formulario Principal). Observemos que la opcin "Lista ->" no tiene subelementos ya que los
crearemos en tiempo de ejecucin

Para crear ventanas nuevas manejaremos el evento clic del men Nueva Ventana.
Debemos crear un nuevo objeto de nuestro formulario base (en nuestro caso FrmChildBase) y
establecer su propiedad MdiParent.

Cdigo para agregar nuevos formularios Child


P g i n a 3 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

Para ordenar nuestras ventanas debemos de manejar el evento clic de nuestro Men Horizontal,
Vertical y Cascada. Para cambiar el ordenamiento de las ventanas existe la funcin
LayoutMdi() que acepta una enumeracin MdiLayout. Aqu el ejemplo de las 3 opciones:

Una gran utilidad es el saber que ventana se encuentra activa, para eso existe la propiedad
ActiveMdiChild que nos devuelve el formulario que se encuentra activo. En nuestro ejemplo
manejaremos el evento clic del men Ventana Activa y tendremos este cdigo:

Tambin podemos tener referencia al control activo con la propiedad ActiveControl de


nuestro formulario activo.
Por ultimo para poder listar los formularios child que se encuentran activos manejaremos el
evento MouseEnter de nuestro men Lista. Esto har que cada vez que pase el mouse sobre el
men Lista se obtenga una referencia de todos los formularios child y se agreguen de forma
dinmica al men. Esto gracias a la propiedad MdiChildren de nuestro formulario principal.
La propiedad MdiChildren nos devuelve un arreglo de formularios.

P g i n a 4 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

P g i n a 5 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

Forms en paneles
Lo primero que vamos a hacer es crear un proyecto de tipo Windows Forms, a este le vamos a
agregar tres Forms (Padre, Hijo1, Hijo2):

Al formulario Padre, le vamos a agregar dos botones (btMostrarHijo1, btMostrarHijo2) y un


panel (panelContenedor), as:

Y en los Forms hijos agregamos etiquetas grandes y distintivas (o lo que quieras agregar), as:

P g i n a 6 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

Ahora, en el lado que nos gusta (el lado del cdigo) veamos cmo implementar estos formularios
en el panel, en el evento click del botn btMostrarHijo1 agregamos el siguiente cdigo:
1
private void btMostrarHijo1_Click(object sender, EventArgs e)
2 {
3
if (this.panelContenedor.Controls.Count > 0)
this.panelContenedor.Controls.RemoveAt(0);
4
Hijo1 form =
5
6 Application.OpenForms.OfType<Hijo1>().FirstOrDefault();
Hijo1 hijo1 = form ?? new Hijo1();
7
hijo1.FormBorderStyle = FormBorderStyle.None;
8
hijo1.Dock = DockStyle.Fill;
this.panelContenedor.Controls.Add(hijo1);
9
this.panelContenedor.Tag = hijo1;
10
hijo1.Show();
11}
12
La explicacin de cmo funciona este cdigo es muy simple, primero preguntamos si existe
algn control en el interior del panel, de ser verdadero lo eliminamos. Luego creamos una nueva
instancia del formulario a agregar Luego preguntamos si existe algn formulario del tipo Hijo1
que ya este abierto, si existe usamos esa misma instancia, de lo contrario creamos una nueva y
sobre este objeto reescribimos algunas de sus propiedades, TopLevel establece si el formulario
debe mostrarse como ventana nivel superior, FormBorderStyle define el estilo de los bordes de
nuestro formulario (en nuestro caso no queremos mostrarlos), Dock establece como se acoplara el
control a su contenedor principal (en nuestro caso queremos que rellene todo el panel), Por
ultimo lo agregamos al panel, establecemos la instancia como contenedor de datos de nuestro
panel y lo mostramos, el resultado se ver as:

P g i n a 7 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

Y si tengo 50 botones en mi formulario padre, tengo que escribir todo este cdigo 50 veces? La
respuesta es NO, por fortuna para nosotros podemos escribir un mtodo que nos ahorre a un ms
el trabajo, en nuestro caso crearemos un mtodo void (sin retorno de datos) que recibir como
parmetro la instancia del Formulario a mostrar, as:
1
2 private void AddFormInPanel(Form fh)
3 {
if (this.panelContenedor.Controls.Count &amp;gt; 0)
4
this.panelContenedor.Controls.RemoveAt(0);
5
fh.TopLevel = false;
fh.FormBorderStyle = FormBorderStyle.None;
6
fh.Dock = DockStyle.Fill;
7
this.panelContenedor.Controls.Add(fh);
8
this.panelContenedor.Tag = fh;
9
fh.Show();
10}
11
Y para acudir a este, desde el evento click del botn lo hacemos as:
1private void btMostrarHijo2_Click(object sender, EventArgs e)
2{
3
var form = Application.OpenForms.OfType<Hijo2>().FirstOrDefault();
Hijo2 hijo = form ?? new Hijo2();
4
AddFormInPanel(hijo);
5
}
6

P g i n a 8 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

CREANDO ARRAY DE CONTROLES CON SUS EVENTOS


Para una aplicacin necesit tener siete CheckBoxes en un formulario indicando los das de la
semana. Tambin tengo un array de variables booleanas llamado "dias" cuyos ndices (0,1,2,3,4,5,6)
representan los das de la semana (L,M,M,J,V,S,D) respectivamente (en C# los ndices de los arrays
empiezan siempre desde cero). Si selecciono el CkeckBox de los das lunes y mircoles solamente, las
variables dias[0] y dias[2] toman el valor de true, el resto de variables "dias" sern false (en la
prctica necesitaba el array "dias" para pasrselo a otra clase y luego usarlo para modificar unos
campos en una BD...)
Esta vez, en lugar de crear cada CheckBox con el diseador del Visual Studio quise crearlos como
elementos de un array de CheckBoxes. Para este tutorial tambin voy a crear un array de TextBoxes
y otro de Buttons.
La declaracin para crear los arrays es como sigue:

Mirando cmo el diseador del Visual Studio declara y asigna las propiedades a los controles, hice lo
mismo para mis arrays de controles, pero dentro de un bucle. Aqu muestro la funcin que crea los
CheckBoxes:

P g i n a 9 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

Dentro del bucle asigno los delegados para los eventos respectivos de cada control. Para saber cul
control del array es el que lanza el evento debo examinar el objeto "sender" que es el control quien
"enva" o lanza el evento. Para saber el ndice del control dentro del array lo almaceno en una
propiedad del control: puede ser el nombre, el TabIndex, o el Tag. En realidad puede ser cualquier
propiedad cuyo valor no vamos a modificar a lo largo de la aplicacin, ya que desde la cual vamos a
saber el ndice del control dentro del array.
Un dato interesante acerca de los eventos es que estos no se ejecutan al declararlos dentro del
bucle que crea los controles. Aqu slo declaramos el evento y lo asignamos a su respectivo control,
el evento recin se ejecuta cuando el control lo "lanza" (es decir: cuando se ejecuta la accin que
llama al evento. Esto me ha recordado un poco a la "Evaluacin Perezosa" de la programacin
funcional, no s si ser exactamente lo mismo, pero se le parece mucho).
Las dos lneas con el comentario "poned un breakpoint ac" hacen exactamente lo mismo: Si deseo
leer el ndice guardado en el nombre del control que lanza el evento, utilizo la variable "n", o ms

P g i n a 10 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

directamente puedo leer el ndice usando la propiedad "Tag". Ambas lneas de cdigo cambian el
valor del elemento con ndice "n" ndice "Tag" (ambos tienen el mismo valor) del array "dias" a
verdadero falso, segn sea el valor de la propiedad "Checked" del CheckBox con ndice "n" "Tag"
dentro del array de ChackBoxes.
Y esta es la funcin de los TextBoxes:

En el caso de los TextBoxes, mandarn un saludo al texto de su formulario (el cual se llama "Form1")
al recibir el cursor (el ndice del respectivo TextBox se lee desde la propiedad "Tag"):

P g i n a 11 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

Si se pone un punto de quiebre en las lneas donde dice "poned un breakpoint ac" se podr ver cmo
la ejecucin del programa "salta" a la declaracin del evento para cambiar los valores a los elementos
del array "dias" cuando se pone o quita el "check" de los CheckBoxes.
Y qu sucede si deseo enviar mensajes a otros formularios? Debo crear un delegado y su respectivo
evento:

P g i n a 12 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

Tambin debo crear el otro formulario que va a recibir los mensajes. Lo he llamado Form2, slo
posee un label llamado "label1" y ste es su cdigo:

P g i n a 13 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

Ahora voy a crear un array de botones en Form1 con los que le mandar mensajes a Form2:

Debo tener cuidado de evaluar que mi evento "Enviar" no sea nulo o lanzar una excepcin. Esto
ocurre si Form2 no se ha cargado. Luego aado un botn desde la barra de herramientas del Visual
Studio con el que abrir Form2:

P g i n a 14 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

El cdigo del nuevo botn (llamado btnForm2) es::

Si ejecuto la aplicacin, y abro tambin Form2, se ver cmo recibe los mensajes desde los botones
creados en el array:

P g i n a 15 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

P g i n a 16 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

Recorrido de todos los controles en un Form C# y VB.NET


Hace un tiempo trabaj en un proyecto en el cual quera "formatear" a los controles de un
formulario, para poder ofrecer al usuario un "skin" o un tema a la aplicacin, por ejemplo, que
todos los controles 'label' de un formulario se colorearan de color azul, para eso lo tena que
hacer dinmicamente, ya que tena varios formularios en la misma aplicacin, y algunos
cargados de distintos tipos de controles.
El recorrido de controles, se puede hacer de 2 maneras:
1. Recorriendo de manera Iterativa los controles de un control. En esta forma, slo podemos
recorrer los controles hijos de un control padre, por ejemplo, si tenemos un Form, y queremos
aplicar este recorrido, entonces unicamente se recorrer todos los controles que estn
directamente agregados en el formulario y no dentro de otro control, es decir, si tenemos 3
controles dentro del Form: 1 Label, 1 GroupBox y 1 Button, pero el Label se encuentra dentro
del Group Box, al hacer este recorrido, no afectar al Label, sino solo al Button y al GroupBox.

Suponiendo que tenemos este formulario, en este


tipo de recorrido, cuando queramos recorrer todos los controles que tenemos en el Form1, solo
recorreremos a GroupBox1 y a Button1.

2. Recorriendo de manera Recursiva TODOS los controles de un control. En esta forma se


podrn recorrer todos y cada uno de los controles que esten dentro de un control padre, an
cuando algunos controles estn dentro de otro y ste a su vez de otro (esto se conoce como
controles anidados), mientras formen parte del mismo control padre que establecemos, se har
dicho recorrido. sta es la mejor manera de hacerlo, cuando se trate de recorrer de manera
DINMICA, es decir, cuando no se conoce ni dnde, ni cuntos controles vamos a recorrer.
Cuando conozcamos su ubicacin, o su tamao, y sabemos que NO VA A CAMBIAR en el
P g i n a 17 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

transcurso de vida de nuestra aplicacin, entonces no conviene hacer un recorrido Recursivo de


todos, sino almacenarlos en una coleccin y ah hacer el recorrido, este tipo de recorrido es sobre
una coleccin de elementos, en la cual conocemos su tamao (esto lo explicar mas adelante).
Cdigo:
1. Recorriendo de manera Iterativa

C#

//Recorremos con un ciclo for each cada control que hay en la coleccion Controls de un objeto
llamado 'control'
foreach(Control contHijo in control.Controls){

//Aqui va la lgica de lo queramos hacer, en mi ejemplo, voy a pintar de color azul el fondo de
todos los controles
contHijo.BackColor = Color.Blue;
}

VB.NET

'Recorremos con un ciclo for each cada control que hay en la coleccion Controls de un objeto
llamado 'control'
For Each contHijo As Control In control.Controls

'Aqui va la lgica de lo queramos hacer, en mi ejemplo, voy a pintar de color azul el fondo de
todos los controles
contHijo.BackColor = Color.Blue
Next

2. Recorriendo de manera Recursiva

C#

public void RecControles(Control control) {


//Recorremos con un ciclo for each cada control que hay en la coleccin Controls
foreach(Control contHijo in control.Controls){
P g i n a 18 | 19

Progamacion Visual

TEMA 5

FORMULARIOS Y CONTROLES MULTIPLES

//Preguntamos si el control tiene uno o mas controles dentro del mismo con la propiedad
'HasChildren'
//Si el control tiene 1 o ms controles, entonces llamamos al procedimiento de forma recursiva,
para que siga recorriendo los dems controles
if (contHijo.HasChildren) this.RecControles(contHijo);
//Aqui va la lgica de lo queramos hacer, en mi ejemplo, voy a pintar de color azul el fondo de
todos los controles
contHijo.BackColor = Color.Blue;
}
}

VB.NET

Public Sub RecControles(ByVal control As Control)


'Recorremos con un ciclo for each cada control que hay en la coleccin Controls
For Each contHijo As Control In control.Controls
'Preguntamos si el control tiene uno o mas controles dentro de l mismo con la propiedad
'HasChildren'
'Si el control tiene 1 o ms controles, entonces llamamos al procedimiento de forma recursiva,
para que siga
'recorriendo los dems controles
If contHijo.HasChildren Then Me.RecControles(contHijo)
'Aqui va la lgica de lo queramos hacer, en mi ejemplo, voy a pintar de color azul el fondo de
todos los controles
contHijo.BackColor = Color.Blue
Next
End Sub
Como se dan cuenta, en el recorrido de forma recursiva, se debe hacer uso de un procedimiento
que haga el recorrido (de ah su nombre, una funcin [o procedimiento] que se llama a s misma,
mientras que de manera iterativa lo puedes utilizar en tu cdigo de funcin o procedimiento sin
necesidad de declarar otra funcin alterna.
Ahora bien, esto lo hace de maravilla, y est bien hacerlo cuando NO conozcamos el tamao ni
la ubicacin de los controles, ya que como ven, el recorrido pasa por TODOS los controles de un
cierto control, pero... y qu pasa si slo necesito los controles 'Button' que se encuentran en un
formulario que, de antemano, s que no voy a agregar otros controles, pues entonces lo que
conviene es que realices una coleccin de esos botones y hagas el recorrido UNICAMENTE en
esos controles. La coleccin la puedes hacer en un Array, en un objeto Collection, etc.

P g i n a 19 | 19

You might also like