Índice de la sección dedicada a .NET (en el Guille) Cómo... en .NET

Manejar formularios hijos en aplicaciones MDI

Publicado el 08/Ene/2006
Actualizado el 11/Ene/2006
Autor: Guillermo 'guille' Som

 

Código para Visual Basic.NET (VB.NET)

Código para C Sharp (C#)

En este artículo veremos un ejemplo simple de cómo manejar los formularios hijos mostrados en una aplicación de tipo MDI (Multiple Document Interface o interfaz de múltiples documentos). Básicamente nos centraremos en la forma de mostrar los formularios hijos, saber cual es el que debemos cerrar y mostrarlos a pantalla completa. Además de que valores debemos asignar para que nuestra aplicación se convierta en una aplicación MDI.

 

Lo que veremos en este artículo y el ejemplo en el que se basa:

En el ejemplo que te mostraré vamos a crear una aplicación MDI en la que tendremos un formulario principal en el que añadiremos un menú con opciones para:
Crear nuevos documentos, abrir un fichero de texto para mostrar en el documento activo, una opción para guardar el fichero del documento activo, otra para cerrar el documento activo y una lista con los documentos que están abiertos.

En el formulario que usaremos para cada nuevo documento simplemente tendremos una caja de textos multilínea en la que mostraremos el fichero abierto.

Como ves no he dejado de repetir que las opciones del formulario principal se basará en el documento activo, esa "pesadez", (que no se puede solucionar con un vaso de sal de frutas, je, je), en decir que se trata del documento activo es para que quede claro que cualquier acción que hagamos con las opciones de los menús se basarán en el documento o formulario secundario que tenga el foco, es decir, el activo.

En realidad podríamos hacerlo de otra forma: Usando menús propios en el formulario hijo, pero como hacer eso necesita algo de más explicación, lo dejaré para otra ocasión, en la que también veremos cómo mezclar los menús del formulario principal y los del formulario hijo. Así que... tendrás que estar pendiente, je, je, je.

 

Nota:
Te recuerdo que, como es costumbre, en este artículo te muestro tanto el código fuente para Visual Basic como el código fuente para C#, en este artículo he usado la versión 2003 de Visual Studio .NET, pero también he publicado este mismo ejemplo para la versión 2005 de Visual Basic y Visual C# 2005.

 

Crear el proyecto de ejemplo

Creamos un nuevo proyecto, se añade un formulario llamado Form1, le dejamos ese nombre. El form se muestra por defecto, por tanto vamos a la ventana de propiedades (si no está activa, puedes pulsar F4), buscamos la propiedad IsMdiContainer y le asignamos el valor True (por defecto tiene el valor False).
A partir de ahora ya tenemos un formulario MDI principal, y notaremos que es así porque el fondo del formulario cambia de color usando el que tengamos predeterminado en el sistema, normalmente es un fondo gris oscuro.

Para añadir el formulario hijo, el que contendrá cada uno de los documentos, simplemente añádelo desde el menú Proyecto>Agregar Windows Forms, dejamos el nombre que le da por defecto: Form2.

Añadimos un textbox, y asignamos la propiedad MultiLine a True, el tipo de letras lo puedes poner como Courier New, también debes asignar a la propiedad Dock el valor Fill (el botón que hay en el centro de las opciones que te muestra al seleccionar esa propiedad desde la ventana de propiedades).

 

Añadir los menús al formulario MDI principal

Ahora añadimos un menú principal, del Cuadro de herramientas seleccionamos MainMenu, y agregamos los siguientes menús:
(entre paréntesis está el nombre del menú)

Hay que resaltar que en el menú Ventanas debemos asignar un valor True a la propiedad MdiList, con idea de que se muestre una lista de todas las ventanas que tengamos abiertas y podamos acceder fácilmente desde la lista que el propio runtime de .NET rellenará conforme vayamos abriendo o cerrando ventanas.

En los separadores no he puesto el nombre porque no los usamos en el código, pero yo suelo nombrarlos al estilo de mnuFicSepN donde N es un número que voy incrementando.

 

Mostrar un nuevo formulario hijo

El menú Nuevo lo usaremos para añadir o abrir nuevas ventanas de documentos (Form2), para que un formulario sea un formulario hijo del form principal, tenemos que asignar a la propiedad MdiParent del formulario hijo el formulario que lo contendrá, para Visual Basic lo haremos con:

<formulario>.MdiParent = Me

Para C# lo haremos de esta otra forma:

<formulario>.MdiParent = this;

 

Para poder crear nuevas ventanas debemos crear nuevas instancias del formulario hijo (Form2), esto lo haremos con este código, para VB lo hacemos con:

Dim frm2 As New Form2

Para C# lo hacemos con:

Form2 frm2 = new Form2();

 

Después asignamos la propiedad MdiParent y finalmente mostramos el formulario recién creado con frm2.Show().

 

Mostrar el formulario hijo maximizado al crearlo

Si queremos que el formulario recién creado se muestre maximizado o minimizado podemos asignar el valor que queramos a la propiedad WindowState del objeto que acabamos de crear: (para C# añade un ; al final)

frm2.WindowState = FormWindowState.Maximized

Esta línea de código la pondremos antes de llamar al método Show.

 

Cerrar el formulario hijo que esté activado

Cuando pulsamos en la opción Cerrar ventana del menú Ficheros, debemos averiguar cual es el formulario que actualmente tiene el foco, esto lo averiguamos usando la propiedad ActiveMdiChild del formulario principal. Debido a que esa propiedad es del tipo Form, debemos hacer una conversión al tipo adecuado, en nuestro caso del tipo Form2, al menos si tenemos activado la comprobación estricta, que es como siempre debe estar: Option Strict On, y si eres de los que no suelen tener esa opción conectada... pues si quieres llevarte bien conmigo... debes tener siempre activada esa opción.

Sigamos, en C# no hace falta tener activada la opción estricta porque siempre hay que hacer las conversiones de forma "correcta", así que... veamos tanto el código de VB como el de C# para saber cual es el formulario hijo que está activo, además en la misma asignación declaramos una variable del tipo Form2.

Dim frm2 As Form2 = CType(Me.ActiveMdiChild, Form2)
Form2 frm2 = (Form2)this.ActiveMdiChild;

 

Una vez que tenemos el formulario hijo que está activo, podemos llamar al método Close para cerrarlo, pero... je, je, sí, siempre hay (o puede haber) un pero... es posible que no haya ningún formulario activo, por ejemplo si no tenemos ningún documento abierto, por tanto deberíamos comprobar si esa variable (frm2) tiene un valor nulo, y en caso de que no sea así, podremos llamar de forma segura al método Close, veamos el código de VB y C#:

If Not frm2 Is Nothing Then
    frm2.Close()
End If
if( frm2 != null )
{
    frm2.Close();
}

 

 

Abrir y Guardar el contenido del textbox del formulario activo

El código de los métodos de Abrir y Guardar no creo que te resulte complicado adivinarlo, lo que debemos tener en cuenta es que cuando seleccionemos el fichero que queremos abrir, tendremos que asignarlo al control textbox del formulario hijo, y cuando vayamos a guardar, usaremos ese contenido para grabarlo en el fichero que seleccionemos.

Pero aquí se nos presenta el mismo caso que a la hora de cerrar la ventana activa, debemos usar un código parecido al que mostramos antes, ya que si no hay ningún formulario activo no deberíamos hacer nada de lo que se supone que podemos hacer con esas dos opciones del menú.

El código lo puedes ver más abajo, tanto para VB como para C#.

 

Nota:
Una cosa que debemos tener presente es que los controles que añadimos en los formularios de C# por defecto están declarados como private, por tanto no podemos acceder desde fuera del propio formulario, por tanto debemos declarar el textbox como internal o public, ya que sino lo hacemos, no podremos acceder desde la variable que crearemos en el método del evento.

En Visual Basic no tenemos ese problema de "acceso" a los controles de los formularios porque siempre están declarados como Friend, que es el equivalente a internal de C#.

 

 

Minimizar todas las ventanas hijas

En el menú Ventanas, que como hemos comentado se añadirán las ventanas hija que tengamos abiertas, también hemos añadido una opción para minimizarlas todas, para ello usaremos la colección MdiChildren del formulario principal.

El código es tan simple como recorrer un array de tipo Form y asignar el valor adecuado al método WindowState:

For i As Integer = 0 To Me.MdiChildren.Length - 1
    Me.MdiChildren(i).WindowState = FormWindowState.Minimized
Next

 

for(int i= 0; i < this.MdiChildren.Length; i++)
{
    this.MdiChildren[i].WindowState = FormWindowState.Minimized;
}

 

Conclusión y el código completo en formato ZIP

Y esto es todo amigos... Como has podido comprobar no era tan complicado, pero si no se saben "las triquiñuelas", pues no tenemos nada que hacer.

En otro artículo te mostraré cómo usar menús en los dos formularios, el principal y el hijo y también veremos cómo mezclar los menús de los dos formularios.

Te recuerdo que la versión para VB 2005 y C# 2005 también la puedes ver en la sección de Visual Studio 20005 (.NET 2.0), en el caso de C# no ha cambiado mucho el código, y en el de VB veremos las dos formas de hacerlo, que es usando las instancias predeterminadas de los formularios, y también sabrás porqué no debes usar esas instancias predeterminadas... o al menos porqué no deberías usarlas.

También veremos cómo añadir la lista de ventanas abiertas en los menús, pero esos menús, en lugar de ser del tipo "normal", veremos los menús del tipo MenuStrip, que como verás cambia la cosa un "poco", pero eso será otro día, y en la sección del .NET 2.0 (lo mismo cuando lo leas ya está publicado).

 

¡Que lo MDI-lices bien!

Nos vemos.
Guillermo

 

El código fuente tanto para VB como C# 2003 en formato ZIP:

El código de VB y C# (VS2003): aplicacionesMDI_vs2003.zip - 24.6 KB

(MD5 checksum: C20B38156887E3713BE3F83A9E1028C2)

 

 


Código para Visual Basic.NET (VB.NET)El código para VB .NET

 

Private Sub mnuNuevo_Click( _
                ByVal sender As System.Object, _
                ByVal e As System.EventArgs) _
                Handles mnuNuevo.Click
    ' Crear una nueva ventana hija
    Dim frm2 As New Form2
    frm2.MdiParent = Me
    ' Para mostrarlo maximizado al crear la ventana
    frm2.WindowState = FormWindowState.Maximized
    frm2.Show()
End Sub

Private Sub mnuSalir_Click( _
                ByVal sender As System.Object, _
                ByVal e As System.EventArgs) _
                Handles mnuSalir.Click
    ' Cerrando la ventana principal se cierran todas
    Me.Close()
    'Application.Exit()
End Sub

Private Sub mnuCerrar_Click( _
                ByVal sender As System.Object, _
                ByVal e As System.EventArgs) _
                Handles mnuCerrar.Click
    ' Cerrar la ventana hija que tiene el foco
    ' Asignar la ventana que tiene el foco
    Dim frm2 As Form2 = CType(Me.ActiveMdiChild, Form2)
    If Not frm2 Is Nothing Then
        frm2.Close()
    End If
End Sub

Private Sub mnuAbrir_Click( _
                ByVal sender As System.Object, _
                ByVal e As System.EventArgs) _
                Handles mnuAbrir.Click
    Dim frm2 As Form2 = CType(Me.ActiveMdiChild, Form2)
    If Not frm2 Is Nothing Then
        ' Seleccionar el fichero que queremos abrir
        Dim ofD As New OpenFileDialog
        If ofD.ShowDialog() = DialogResult.OK Then
            ' Leemos el contenido de ese fichero
            Dim sr As New System.IO.StreamReader(ofD.FileName, System.Text.Encoding.Default, True)
            ' Lo asignamos al TextBox1 del Form2:
            frm2.TextBox1.Text = sr.ReadToEnd()
            sr.Close()
        End If
    End If
End Sub

Private Sub mnuGuardarComo_Click( _
                ByVal sender As System.Object, _
                ByVal e As System.EventArgs) _
                Handles mnuGuardarComo.Click
    Dim frm2 As Form2 = CType(Me.ActiveMdiChild, Form2)
    If Not frm2 Is Nothing Then
        Dim sfD As New SaveFileDialog
        If sfD.ShowDialog() = DialogResult.OK Then
            Dim sw As New System.IO.StreamWriter(sfD.FileName, False, System.Text.Encoding.Default)
            sw.WriteLine(frm2.TextBox1.Text)
            sw.Close()
        End If
    End If
End Sub

Private Sub mnuMinimizarTodas_Click( _
                ByVal sender As System.Object, _
                ByVal e As System.EventArgs) _
                Handles mnuMinimizarTodas.Click
    For i As Integer = 0 To Me.MdiChildren.Length - 1
        Me.MdiChildren(i).WindowState = FormWindowState.Minimized
    Next
End Sub

 


Código para C Sharp (C#)El código para C#

 

/// <summary>
/// Punto de entrada principal de la aplicación.
/// </summary>
[STAThread]
static void Main() 
{
    Application.Run(new Form1());
}

private void mnuNuevo_Click(System.Object sender, System.EventArgs e) 
{
    // Crear una nueva ventana hija
    Form2 frm2 = new Form2();
    frm2.MdiParent = this;
    // Para mostrarlo maximizado:
    frm2.WindowState = FormWindowState.Maximized;
    frm2.Show();
}  

private void mnuSalir_Click(System.Object sender, System.EventArgs e) 
{
    // Cerrando la ventana principal se cierran todas
    this.Close();
    //Application.Exit()
}  

private void mnuCerrar_Click(System.Object sender, System.EventArgs e) 
{
    // Cerrar la ventana hija que tiene el foco
    // Asignar la ventana que tiene el foco
    Form2 frm2 = (Form2)this.ActiveMdiChild;
    if( frm2 != null )
    {
        frm2.Close();
    }
}  

private void mnuAbrir_Click(System.Object sender, System.EventArgs e) 
{
    Form2 frm2 = ((Form2)this.ActiveMdiChild);
    if( frm2 != null )
    {
        // Seleccionar el fichero que queremos abrir
        OpenFileDialog ofD = new OpenFileDialog();
        if( ofD.ShowDialog() == DialogResult.OK )
        {
            // Leemos el contenido de ese fichero
            System.IO.StreamReader sr = 
                new System.IO.StreamReader(ofD.FileName, System.Text.Encoding.Default, true);
            // Lo asignamos al TextBox1 del Form2:
            frm2.textBox1.Text = sr.ReadToEnd();
            sr.Close();
        }
     }
}  

private void mnuGuardarComo_Click(System.Object sender, System.EventArgs e) 
{
    Form2 frm2 = ((Form2)this.ActiveMdiChild);
    if( frm2 != null )
    {
        SaveFileDialog sfD = new SaveFileDialog();
        if( sfD.ShowDialog() == DialogResult.OK )
        {
            System.IO.StreamWriter sw = 
                new System.IO.StreamWriter(sfD.FileName, false, System.Text.Encoding.Default);
            sw.WriteLine(frm2.textBox1.Text);
            sw.Close();
        }
    }
}  

private void mnuMinimizarTodas_Click(System.Object sender, System.EventArgs e) 
{
    for(int i= 0; i < this.MdiChildren.Length; i++)
    {
        this.MdiChildren[i].WindowState = FormWindowState.Minimized;
    }
}

 


Ir al índice principal de el Guille