none
Error no controlado windows forms RRS feed

  • Pregunta

  • Hola

    Desarrolle una aplicación en Windows forms que lo que hace es comunicarse por puerto serial a un dispositivo X, este dispositivo le entrega información a la aplicación, luego dentro de la aplicación hay unos controles personalizados que desarrolle que se pintan cada vez que se le renuevan los datos a las variables encargadas de realizar el pintado ... El pintado lo realizo de la siguiente forma:

     protected override void OnPaint(PaintEventArgs e)
            {
                try
                {
                    base.OnPaint(e);
                    Graphics g = e.Graphics;
    
                    SolidBrush myBrush = new System.Drawing.SolidBrush(Color.White);
    
                    Rectangle rectangulo = new Rectangle(55, 32, 118, 21);
                    Rectangle rectanguloMascara = new Rectangle((int)(55 + (PotFor * 1.2)), 32, (int)(120 - (PotFor * 1.2)), 21);
                    lblPF.Text = PotFor.ToString() + " W";
                    LinearGradientBrush myLinearGradientBrush = new LinearGradientBrush(rectangulo, Color.Orange, Color.Red, LinearGradientMode.Horizontal);
                    g.FillRectangle(myLinearGradientBrush, rectangulo);
                    g.FillRectangle(myBrush, rectanguloMascara);
    
                    rectangulo = new Rectangle(55, 61, 118, 21);
                    rectanguloMascara = new Rectangle((int)(55 + (Tem * 1.2)), 61, (int)(120 - (Tem * 1.2)), 21);
                    lblTM.Text = Tem.ToString() + " °C";
                    myLinearGradientBrush = new LinearGradientBrush(rectangulo, Color.Green, Color.Red, LinearGradientMode.Horizontal);
                    g.FillRectangle(myLinearGradientBrush, rectangulo);
                    g.FillRectangle(myBrush, rectanguloMascara);
    
                    rectangulo = new Rectangle(55, 90, 118, 21);
                    rectanguloMascara = new Rectangle((int)(55 + (PotRev * 1.2)), 90, (int)(120 - (PotRev * 1.2)), 21);
                    lblPR.Text = PotRev.ToString() + " W";
                    myLinearGradientBrush = new LinearGradientBrush(rectangulo, Color.Orange, Color.Red, LinearGradientMode.Horizontal);
                    g.FillRectangle(myLinearGradientBrush, rectangulo);
                    g.FillRectangle(myBrush, rectanguloMascara);
    
                    myLinearGradientBrush.Dispose();
                    myBrush.Dispose();
                    g.Dispose();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error pintando barras " + ex.Message);
                }
            }

    Como veran, cada nada se vuelve a pintar el formulario. Sin embargo cuando inicio el programa todo va bien, hasta que de repente el programa se bloquea y no puedo capturar la exepcion por ningun lado, lo unico que puedo hacer es revisar en el log de eventos del SO y lo que dice alli es error de ApplicationHang. El control personalizado creado lo refresco con el metodo invalidate(); pero aun asi colocando una exepcion que capture el error no se la verdad donde se genera el error. Ahora bien, la aplicacion corre todo el tiempo con hilos pues por que tiene que averiguar el estado de ciertos equipos de hardware, pero la verdad no se como capturar la aplicacion, no se si es cuestion de como esta desarrollado el aplicativo, posiblemente, pero me gustaria aun asi poder capturar la exepcion ...

    Gracias !!

    miércoles, 28 de noviembre de 2012 1:47

Todas las respuestas

    1. Si mal no recuerdo, no debe disponerse del objeto Graphics de OnPaint porque eso ya se hace automáticamente.
    2. Usted crear 3 LinearGradientBrush's pero únicamente dispone de 1 (el último).  Eso quiere decir que está dejando 2 objetos gráficos desperdiciados cada vez que pinta.

    El síntoma que usted describe es típico de objetos GDI dejados atrás.  Por eso siempre es bueno usar using().


    Jose R. MCP
    Code Samples

    miércoles, 28 de noviembre de 2012 2:32
    Moderador
  • Hola

    Bueno, si efectivamente estaba dejando dos objetos hay sueltos y no les hacia el dispose(); ahora bien, Cambiando el método un poco para no declarar un objeto de tipo Graphics hice lo siguiente:

     e.Graphics.FillRectangle(myLinearGradientBrush, rectangulo);

    Pero entonces es necesario invocar el Dispose() de este objeto ?? e.Dispose() ??

    Gracias


    miércoles, 28 de noviembre de 2012 2:50
  • No se hace el llamado de e.Graphics.Dispose().

    Jose R. MCP
    Code Samples

    miércoles, 28 de noviembre de 2012 2:58
    Moderador
  • Hola

    Con respecto a la aplicacion que comento muestro a continuacion el codigo de una clase que utilzo para aplicar transformaciones visuales sobre controles personalizados:

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace MonitorControl
    {
        public partial class MonitorPPTB : UserControl
        {
            public bool Encendido { get; set; }
            public string NombreAplicacion { get; set; }
            public double VoltajeFuenteEsperado { get; set; }
            public bool HiloVoltajeInferiorCorriendo { get; set; }
            public bool HiloFallaVoltajeAltoAC { get; set; }
    
            #region Eventos estados de modulos y equipo
    
            private event CambiarEstadoModuloHorizontal EventoCambiarEstadoModulo;
            private event CambiarEstadoEquipo EventoCambiarEstadoEquipo;
            //private event PintarBarras EventoPintarBarras;
    
            #endregion
    
            public MonitorPPTB()
            {
                InitializeComponent();
    
                #region Eventos
    
                EventoCambiarEstadoModulo += new CambiarEstadoModuloHorizontal(EventoModulo);
                EventoCambiarEstadoEquipo += new CambiarEstadoEquipo(EventoEquipo);
                //EventoPintarBarras += new PintarBarras(EventoBarras);
                #endregion
            }
    
            #region Administracion comportamiento modulos y equipos
    
            public void EventoModulo(BarraControl.BarrasHorizontal modulo, bool estado)
            {
                CambiarEstadoModuloHorizontal delegadoCambiarEstadoModulo = new CambiarEstadoModuloHorizontal(AplicarCambioModulo);
                this.Invoke(delegadoCambiarEstadoModulo, new object[] { modulo, estado });
            }
    
            public void EventoEquipo(bool estado)
            {
                CambiarEstadoEquipo delegadoCambiarEstadoEquipo = new CambiarEstadoEquipo(AplicarCambioEquipo);
                this.Invoke(delegadoCambiarEstadoEquipo, new object[] { estado });
            }
    
            //public void EventoBarras(BarraControl.BarrasHorizontal control, params double[] datos)
            //{
            //    PintarBarras delegadoPintarBarras = new PintarBarras(Pintar);
            //    this.Invoke(delegadoPintarBarras, new object[] { control, datos });
            //}
    
            public void AplicarCambioModulo(BarraControl.BarrasHorizontal modulo, bool estado)
            {
                if (Bloqueador.DAL.EstadoControl.BotonHabilitado(modulo.btnEstado))
                {
                    if (estado)
                    {
                        modulo.btnEstado.Text = "Encendido";
                        modulo.btnEstado.BackColor = Color.ForestGreen;
                        modulo.tltEstadoModulo.SetToolTip(modulo.btnEstado, "Apagar");
                    }
                    else
                    {
                        modulo.btnEstado.Text = "Apagado";
                        modulo.btnEstado.BackColor = Color.DarkSlateBlue;
                        modulo.tltEstadoModulo.SetToolTip(modulo.btnEstado, "Encender");
                        
                    }
    
                    modulo.Encendido = estado;
                }
            }
    
            public void AplicarCambioEquipo(bool estado)
            {
                if (Bloqueador.DAL.EstadoControl.BotonHabilitado(btnEstadoEquipo))
                {
                    if (estado)
                    {
                        btnEstadoEquipo.Text = "Encendido";
                        btnEstadoEquipo.BackColor = Color.ForestGreen;
                        tltEquipo.SetToolTip(btnEstadoEquipo, "Apagar");
                    }
                    else
                    {
                        btnEstadoEquipo.Text = "Apagado";
                        btnEstadoEquipo.BackColor = Color.DarkSlateBlue;
                        tltEquipo.SetToolTip(btnEstadoEquipo, "Encender");
                    }
                }
    
                Encendido = estado;
            }
    
            public void Pintar(BarraControl.BarrasHorizontal control, params double[] datos)
            {
                if (control.InvokeRequired)
                {
                    PintarBarras delegadoPintar = new PintarBarras(Pintar);
                    control.Invoke(delegadoPintar, control, datos);
                }
                else
                {
                    control.PotFor = datos[0];
                    control.Tem = datos[1];
                    control.PotRev = datos[2];
                    //control.PotFor = control.ObtenerDato();
                    //control.Tem = control.ObtenerDato();
                    //control.PotRev = control.ObtenerDato();            
                    control.Invalidate();
                }
            }
    
            public void AplicarCambioEventoModulo(BarraControl.BarrasHorizontal modulo, bool estado)
            {
                EventoCambiarEstadoModulo(modulo, estado);
            }
    
            public void AplicarCambioEventoEquipo(bool estado)
            {
                EventoCambiarEstadoEquipo(estado);
            }
    
            //public void AplicarEventoPintar(BarraControl.BarrasHorizontal control, params double[] datos)
            //{
            //    EventoPintarBarras(control, datos);
            //}
    
            #endregion
    
            /// <summary>
            /// Carga datos del equipo
            /// </summary>
            /// <param name="datos"></param>
            /// <param name="falla"></param>
            public void CargarControlValores(object[] datos, bool falla, ref bool invocar, bool fallos, ref bool apagarEquipoVoltajeFuenteInferior)
            {
                AplicarCambioEventoEquipo(Convert.ToBoolean(datos[0]));
    
                txtEstadoBateria.Text = datos[1].ToString();
                txtFallas.Text = datos[2].ToString();
    
                if (falla)
                {
                    txtFallas.BackColor = System.Drawing.Color.Red;
                    txtFallas.ForeColor = System.Drawing.Color.White;
    
                    if (Encendido)
                    {
                        invocar = true;
                    }
                }
                else
                {
                    txtFallas.BackColor = pnlControl.BackColor;
                    txtFallas.ForeColor = System.Drawing.Color.Black;
                }
    
                txtFuente.Text = datos[3].ToString() + " DC";
    
                if (Convert.ToDouble(datos[3]) < VoltajeFuenteEsperado)
                {
                    apagarEquipoVoltajeFuenteInferior = true;
                }
    
                txtCorrienteBaterias.Text = datos[4].ToString() + " A";
                txtNivelCarga.Text = datos[5].ToString();
    
                txtEstadoAC.Text = datos[6].ToString();
    
                if (fallos)
                {
                    txtEstadoAC.BackColor = System.Drawing.Color.Red;
                    txtEstadoAC.ForeColor = System.Drawing.Color.White;
                }
                else
                {
                    txtEstadoAC.BackColor = pnlControl.BackColor;
                    txtEstadoAC.ForeColor = System.Drawing.Color.Black;
                }
            }
            /// <summary>
            /// Pinta las barras
            /// </summary>
            /// <param name="datosBarras"></param>
            public void CargarControlValores(List<MetaDataMonitor> datosBarras)
            {
                Pintar(bahModuloUno, datosBarras[0].PotenciaForward, datosBarras[0].Temperatura, datosBarras[0].PotenciaReverse);
                Pintar(bahModuloDos, datosBarras[1].PotenciaForward, datosBarras[1].Temperatura, datosBarras[1].PotenciaReverse);
                Pintar(bahModuloTres, datosBarras[2].PotenciaForward, datosBarras[2].Temperatura, datosBarras[2].PotenciaReverse);
    
                #region Estado Modulos
    
                AplicarCambioEventoModulo(bahModuloUno, Convert.ToBoolean(datosBarras[0].Estado));
                AplicarCambioEventoModulo(bahModuloDos, Convert.ToBoolean(datosBarras[1].Estado));
                AplicarCambioEventoModulo(bahModuloTres, Convert.ToBoolean(datosBarras[2].Estado));
    
                #endregion
            }
            /// <summary>
            /// Cambia el estado del boton del equipo
            /// </summary>
            /// <param name="idBoton"></param>
            /// <param name="estado"></param>
            public void CargarControlValores(int idBoton, bool estado)
            {
                switch (idBoton)
                {
                    case 1:
    
                        AplicarCambioEventoModulo(bahModuloUno, estado);
                        break;
                    case 2:
    
                        AplicarCambioEventoModulo(bahModuloDos, estado);
                        break;
                    case 3:
    
                        AplicarCambioEventoModulo(bahModuloTres, estado);
                        break;
                    default:
    
                        AplicarCambioEventoEquipo(estado);
                        break;
                }
            }
    
            public BarraControl.BarrasHorizontal ObtenerControl(int idControl)
            {
                switch (idControl)
                {
                    case 1:
                        return bahModuloUno;                    
                    case 2:
                        return bahModuloDos;
                    case 3:
                        return bahModuloTres;
                    default:
                        return null;
                }
            }
        }
    }
    

    El codigo lo modifique un poco de acuerdo a cuestiones que vi de llamado de controles sobre hilos, resulta que cuando inicio la aplicacion esta comienza a crecer en cuanto consumo de bytes .. Eso no me gusta, la idea es que la aplicacion solo utilice cierta cantidad de memoria y que esta no aumente con respecto al tiempo ... para el pintado de controles lo hago sobre hilos por que aveces el pintado se demora un poco, entonces pues disparo un hilo de la siguiente forma ...

    new Thread(new ThreadStart(() => MetodoEjecutar()));

    No lo controlo en cuanto al abort del hilo debido a que pues no es necesario ya que apenas termina de pintar pues se acabo el hilo .... Es correcto lanzar el pintado de controles sobre un hilo ??

    Inclusive muchos metodos los disparo sobre un hilo tal como el ejemplo, no se hasta que punto sera necesario realizarlo de esa forma ...

    Gracias !!

    miércoles, 28 de noviembre de 2012 16:34
  • Y si pruebas a introducir en cada uno de los métodos el try/catch y así poder ver de dónde viene el error? 

    Un saludo


    TopCoder algorythm addict! C# addict!
    Twitter
    LinkedIn

    miércoles, 5 de diciembre de 2012 15:49