Saltar al contenido

P2/ Formulario Plano, Sin Bordes y Moderno con Menú animado Efecto Sliding, One Window, Versión Completa/ C#, WinForm + Pasar Datos entre Forms

Hola, ahora completaremos el formulario moderno de la parte 1, con las funcionalidades faltantes, como poder redimensionar el formulario, solucionar el inconveniente de maximizar y restaurar (Al maximizar, el formulario se ocupa todo el fondo de escritorio). También realizaremos algunos comentarios que hicieron, estas son: Pasar datos de entre formularios (Form Padre a Form Hijo y viceversa), Mostrar un formulario hijo en el mismo panel, finalmente mostrar un mensaje de alerta antes de cerrar la aplicación.

Crearemos el formulario desde cero para no enredarnos y tener fallas o problemas, bien empecemos con el tutorial.

Paso 1: Crear Proyecto y Formulario de Menú Principal

  • Creamos proyecto de aplicación de Windows Form en C#.
  • Quitamos el borde del formulario: Propiedad-> FormBorderStyle=None
  • Asignamos el tamaño al formulario: Propiedad-> Size= 1100; 600
  • Establecemos el tamaño mínimo del formulario: Propiedad-> MinimumSize= 680; 500

Al establecer la propiedad estilo de borde a ninguno del formulario, este pierde la funcionalidad de poder cambiar de tamaño, es decir, ya no es posible estirar el formulario para cambiar de tamaño, para solventar el problema, hacemos lo siguiente.

Paso 2: Crear Función de Redimensionar el Formulario (Panel Contenedor Principal)

  • Agregamos un Panel como Contenedor Principal para otros paneles y formularios.
  • Establecemos la propiedad BackColor = ActiveCaption (OPCIONAL)
  • Establecemos la propiedad Dock = Fill
  • Asignamos un nombre al panel: Name = “PanelContenedorPrincipal”
  • El diseño de debió haber quedado de la siguiente manera:
  • Ahora es momento de codificar la funcionalidad de redimensionar el formulario a través de Panel Contenedor Principal.

FormMenuPrincipal.cs

//Constructor
        public FormMenuPrincipal()
        {
            InitializeComponent();
            //Estas lineas eliminan los parpadeos del formulario o controles en la interfaz grafica (Pero no en un 100%)
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.DoubleBuffered = true;
        }
        //METODO PARA REDIMENCIONAR/CAMBIAR TAMAÑO A FORMULARIO  TIEMPO DE EJECUCION ----------------------------------------------------------
        private int tolerance = 15;
        private const int WM_NCHITTEST = 132;
        private const int HTBOTTOMRIGHT = 17;
        private Rectangle sizeGripRectangle;

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_NCHITTEST:
                    base.WndProc(ref m);
                    var hitPoint = this.PointToClient(new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16));
                    if (sizeGripRectangle.Contains(hitPoint))
                        m.Result = new IntPtr(HTBOTTOMRIGHT);
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }
        //----------------DIBUJAR RECTANGULO / EXCLUIR ESQUINA PANEL 
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            var region = new Region(new Rectangle(0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height));

            sizeGripRectangle = new Rectangle(this.ClientRectangle.Width - tolerance, this.ClientRectangle.Height - tolerance, tolerance, tolerance);

            region.Exclude(sizeGripRectangle);
            this.panelContenedorPrincipal.Region = region;
            this.Invalidate();
        }
        //----------------COLOR Y GRIP DE RECTANGULO INFERIOR
        protected override void OnPaint(PaintEventArgs e)
        {

            SolidBrush blueBrush = new SolidBrush(Color.FromArgb(55, 61, 69));
            e.Graphics.FillRectangle(blueBrush, sizeGripRectangle);

            base.OnPaint(e);
            ControlPaint.DrawSizeGrip(e.Graphics, Color.Transparent, sizeGripRectangle);
        }

Paso 3: Diseñar Interfaz de Usuario Menú Principal

  • Diseñe el formulario de menú principal sobre el Panel Contenedor Principal. La configuración de las propiedades se describen abajo.
  • Establezca las siguientes propiedades en el form y controles.

Panel Barra Titulo

BackColor = 214; 61; 92
Dock = Top
Name = «PanelBarraTitulo»
Size = 1050, 45

Panel Menú

Name = «PanelMenu»
Dock = Left 
Size = 230, 557
BackColor = 29; 34; 39

Panel Usuario

BackColor = 55; 61; 69
Dock = Bottom

Panel Contenedor de Formularios

BackColor = 64; 69; 76
Dock = Fill
Name = «panelContenedorForm»

Botón Menu (Picture Box)

Cursor = Hand
Name = «btnMenu»
Size = 40 ,40
SizeMode = CenterImage
Image = «btnMenu.Image»

Botones

FlatStyle = Flat
FlatAppearance.BorderSize = 0
FlatAppearance.MouseOverBackColor = 38; 45; 53
Size = 230, 40

Boton Cerrar, Maximizar, Minimizar, Restaurar

Size = 35, 35
Cursor = Hand
Anchor = Top | Right (Responsive)

Timer Expandir Menu – Contraer Menú

Interval= 15

Timer Hora y Fecha

Interval= 100
Enable= true

Paso 4: Crear Menú Animado con efecto Desplazamiento (Sliding Menu)

  • Ahora codificaremos la opción de contraer y expandir el panel menú vertical con efecto corredizo o desplazamiento; para ello:
    Creamos el evento Tick de Timer Contraer Menú.
    Creamos el evento Tick de Timer Expandir Menú.
    Creamos el evento Click del Botón Menú
    .
  • Codificamos de la siguiente manera:
        private void btnMenu_Click(object sender, EventArgs e)
        {
            //-------CON EFECTO SLIDING
            if (panelMenu.Width == 230)
            {
                this.tmContraerMenu.Start();
            }
            else if (panelMenu.Width == 55)
            {
                this.tmExpandirMenu.Start();
            }            
        }

        private void tmExpandirMenu_Tick(object sender, EventArgs e)
        {
            if (panelMenu.Width >= 230)
                this.tmExpandirMenu.Stop();
            else
                panelMenu.Width = panelMenu.Width + 5;
            
        }

        private void tmContraerMenu_Tick(object sender, EventArgs e)
        {
            if (panelMenu.Width <= 55)
                this.tmContraerMenu.Stop();
            else
                panelMenu.Width = panelMenu.Width - 5;
        }

Paso 5: Crear Función de Cerrar, Maximizar/Restaurar y Minimizar el formulario.

  • Creamos los eventos Click de cada botón, y codificamos de la siguiente manera:
        int lx, ly;
        int sw, sh;
        private void btnMaximizar_Click(object sender, EventArgs e)
        {
            lx = this.Location.X;
            ly = this.Location.Y;
            sw = this.Size.Width;
            sh = this.Size.Height;
            this.Size = Screen.PrimaryScreen.WorkingArea.Size;
            this.Location = Screen.PrimaryScreen.WorkingArea.Location;
            btnMaximizar.Visible = false;
            btnNormal.Visible = true;

        }

        private void btnNormal_Click(object sender, EventArgs e)
        {
            this.Size = new Size(sw, sh);
            this.Location = new Point(lx, ly);
            btnNormal.Visible = false;
            btnMaximizar.Visible = true;
        }

        private void btnMinimizar_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }

        private void btnCerrar_Click(object sender, EventArgs e)
        {           
                Application.Exit();            
        }

 Paso 6: Crear Función de Arrastrar el formulario (Drag Form)

  • Importamos la librería  System.Runtime.InteropServices, y agregamos los siguientes fragmentos de código.
        [DllImport("user32.DLL", EntryPoint = "ReleaseCapture")]
        private extern static void ReleaseCapture();

        [DllImport("user32.DLL", EntryPoint = "SendMessage")]
        private extern static void SendMessage(System.IntPtr hWnd, int wMsg, int wParam, int lParam);
  • Creamos el evento MouseDown del Panel Barra de Titulo, e invocamos los métodos anteriores creados.
        private void PanelBarraTitulo_MouseDown(object sender, MouseEventArgs e)
        {
            ReleaseCapture();
            SendMessage(this.Handle, 0x112, 0xf012, 0);
        }

Paso 5: Inicializar Reloj en Tiempo Real (Opcional)

  • Creamos el evento Tick de Timer Hora y Fecha, y codificamos de la siguiente manera.
        private void tmFechaHora_Tick(object sender, EventArgs e)
        {
            lbFecha.Text = DateTime.Now.ToLongDateString();
            lblHora.Text = DateTime.Now.ToString("HH:mm:ssss");
        }

Paso 6: Crear Método para Abrir formularios en el panel Contenedor.

        private void AbrirFormEnPanel(object formHijo)
        {
            if (this.panelContenedorForm.Controls.Count > 0)
                this.panelContenedorForm.Controls.RemoveAt(0);
            Form fh = formHijo as Form;
            fh.TopLevel = false;
            fh.FormBorderStyle = FormBorderStyle.None;
            fh.Dock = DockStyle.Fill;            
            this.panelContenedorForm.Controls.Add(fh);
            this.panelContenedorForm.Tag = fh;
            fh.Show();
        }

Paso 7: Mostrar Dashboard o Logotipo Simple al Iniciar la aplicación y al Cerrar Formularios.

  • Creamos un Formulario para mostrar el sumario/Resumen de la aplicación o un Logotipo Simple.
  • Creamos un método para abrir el Formulario Inicio/Logo
        private void MostrarFormLogo()
        {
            AbrirFormEnPanel(new FormLogo());
        }
  • Invocamos el método anterior desde el Evento load para mostrarlo al abrir la aplicación.
        private void FormMenuPrincipal_Load(object sender, EventArgs e)
        {
            MostrarFormLogo();
        }
  • Creamos un método para el evento FormClosedEventArgs del Formulario de Inicio para mostrarlo al cerrar los formularios.
       private void MostrarFormLogoAlCerrarForms(object sender, FormClosedEventArgs e)
        {
            MostrarFormLogo();
        }
  • Abrimos los formularios de la siguiente manera. (Ejemplo Form Lista Clientes – Membresia)
private void btnListaClientes_Click(object sender, EventArgs e)
        {
            FormListaClientes fm = new FormListaClientes();
            fm.FormClosed += new FormClosedEventHandler(MostrarFormLogoAlCerrarForms);
            AbrirFormEnPanel(fm);
        }

        private void btnMembresia_Click(object sender, EventArgs e)
        {
            FormMembresia frm = new FormMembresia();
            frm.FormClosed += new FormClosedEventHandler(MostrarFormLogoAlCerrarForms);
            AbrirFormEnPanel(frm);
        }

RECOMENDACIÓN: Puedes invocar el método MostrarFormLogoAlCerrarForms desde el método AbrirFormEnPanel para no invocarlo desde cada evento click del botón.

Paso Final: Añadir mensaje de alerta antes de cerrar la aplicación.

Modificamos el botón cerrar de la siguiente manera:

        private void btnCerrar_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("¿Está seguro de cerrar?", "Alerta¡¡", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                Application.Exit();
            }
        }

Recomendaciones Finales

Crea los formularios hijos que se abrirán en el panel contenedor de Formulario al mismo tamaño de este, adicionando las dimensiones del borde. para este ejemplo, el tamaño ideal es: 886 de ancho; 496 de alto (El tamaño del panel contenedor de Formulario es 870; 457, a este le sumamos el tamaño de los bordes del form: 16 de ancho, 39 de alto ), de esa manera evitamos que le formulario parpadee al abrir formularios o redimensionar en tiempo de ejecución.

Eso es todo 🙂

Video Tutorial

Otros GUI

C#/ Formulario Plano Moderno Multi Window- WinForm (Oficial – No Beta)

VB/ Formulario Plano Moderno Multi Window- WinForm (Oficial – No Beta)