[C#] DataGridView congelación de app

Iniciado por kondrag_X1, 10 Junio 2015, 10:15 AM

0 Miembros y 1 Visitante están viendo este tema.

kondrag_X1

Hola,

El problema es el siguiente: inserto filas en un datagridview y cuando llega a un determinado número de filas se queda la app congelada y el scroll vertical no aparece si no que hace algo raro. Además tengo la propiedad ScrollBar en Vertical.

Personalmente no sé que puede estar pasando quizas un problema de la interfaz .... ni idea. He estado buscando por internet y a la gente este componente no suele darle muchos problemas.

¿Se os ocurre que puede estar pasando?

#########################
Ya aparece el scroll era simplemente que tenia la propiedad AutoSize = true; y claro había que ponerla a false. Pero el problema sigue existiendo cuando aparece el scroollBar la app se queda congelada.

Eleкtro

#1
Si estás utilizando el método DataGridView.Rows.Add que toma cómo argumento el número de filas a crear, entonces el thread de la UI no se podrá actualizar hasta que finalice dicha operación de inserción de filas, por ende, la UI se congelará.

Habría que ver el código para poder comprobar el qué y cómo lo estás haciendo, ya que quizás haya otros problemas que estén derivando en esa congelación del thread, así que si no das más datos no se te puede ayudar a buscar la solución más eficiente para el problema que sea en cuestión.

De todas formas, puedes añadir las filas de manera asíncrona para solventar el problema de congelación, pero esto tomará bastante más tiempo en añadir todas las filas:

Código (vbnet) [Seleccionar]
Public Class Form1

   Private WithEvents bgw As New BackgroundWorker

   Private Sub Button1_Click(sender As Object, e As EventArgs) _
   Handles Button1.Click

       DataGridView1.ColumnCount = 1
       bgw.RunWorkerAsync()

   End Sub

   Sub DoRowAdd(ByVal dgv As DataGridView, ByVal row As DataGridViewRow)

       If dgv.InvokeRequired Then
           dgv.Invoke(Sub() dgv.Rows.Add(row))

       Else
           dgv.Rows.Add(row)

       End If

   End Sub

   Sub Work(ByVal sender As Object, ByVal e As EventArgs) _
   Handles bgw.DoWork

       For rowIndex As Integer = 0 To Short.MaxValue

           Dim row As New DataGridViewRow
           row.Cells.Add(New DataGridViewTextBoxCell With {.Value = rowIndex})
           Me.DoRowAdd(Me.DataGridView1, row)

       Next rowIndex

   End Sub

End Class


Otra alternativa sería añadir las filas una a una cómo en el ejemplo anterior, pero utilizando el método Application.DoEvents para que tras cada inserción se procese el resto de mensajes (eventos) en cola para actualizar la UI;
el tiempo que se toma en crear las filas es practicamente el mismo que en el ejemplo de arriba.

Código (vbnet) [Seleccionar]
       DataGridView1.Columns.Add(String.Empty, String.Empty)

       For rowIndex As Integer = 0 To Short.MaxValue

           DataGridView1.Rows.Add({rowIndex})
           Application.DoEvents()

       Next rowIndex


También lo que puedes hacer al utilizar el método DataGridView.Rows.Add que toma cómo argumento el número de filas a crear, es suspender la lógica del layout del control, esto aceleraría bastante el tiempo que tarda en agregar todas las filas, pero obviamente no se desbloquearía la UI.

Código (vbnet) [Seleccionar]
       DataGridView1.Columns.Add(String.Empty, String.Empty)
       DataGridView1.SuspendLayout()
       DataGridView1.Rows.Add(Short.MaxValue)
       DataGridView1.ResumeLayout()





EDITO: Ups, perdón, no me di cuenta que lo preguntaste en C#, aquí tienes una conversión online:

Código (csharp) [Seleccionar]

using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
public class Form1
{

private BackgroundWorker withEventsField_bgw = new BackgroundWorker();
private BackgroundWorker bgw {
get { return withEventsField_bgw; }
set {
if (withEventsField_bgw != null) {
withEventsField_bgw.DoWork -= Work;
}
withEventsField_bgw = value;
if (withEventsField_bgw != null) {
withEventsField_bgw.DoWork += Work;
}
}
}

private void Button1_Click(object sender, EventArgs e)
{

DataGridView1.ColumnCount = 1;
bgw.RunWorkerAsync();

}

public void DoRowAdd(DataGridView dgv, DataGridViewRow row)
{

if (dgv.InvokeRequired) {
dgv.Invoke(() => dgv.Rows.Add(row));

} else {
dgv.Rows.Add(row);

}

}

public void Work(object sender, EventArgs e)
{

for (int rowIndex = 0; rowIndex <= short.MaxValue; rowIndex++) {

DataGridViewRow row = new DataGridViewRow();
row.Cells.Add(new DataGridViewTextBoxCell { Value = rowIndex });
this.DoRowAdd(this.DataGridView1, row);

}

}

}

//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================


Considero que los otros dos ejemplos no necesitan una conversión a C# para entenderlos.

Saludos!








kondrag_X1

muchismas gracias Electro voy a probarlo a ver si eso me puede solucionar el problema. Además haciendo pruebas he visto que es cuando inserto fila con "DataGridView.Rows.Add" y se completa el datagrid ocurre esto. Creo que es tema del sincronismo voy a probarlo y os comento.

saludos.

kondrag_X1

#3
Hola de nuevo,

Sinceramente no sé por que ocurre esto: Cuando intento visualizar mas elementos que el tamaño del datagridView no aparece la barra vertical y además la app se queda bloqueada. Estoy implementando tu código adaptandolo pero me da un error diciendo que no se puede convertir una expresión lambda en un System.Delegate. Entiendo lo que me quiere decir pero no se me ocurre como implementarlo.

por ejemplo así: Teniendo un delegado que llame a mi método.

Código (csharp) [Seleccionar]

private void updateVisualizacionMatricula(String texto)
       {
           if (this.InvokeRequired)
           {
               updateVisualizacionMatricula_ d = new updateVisualizacionMatricula_(updateVisualizacionMatricula);
               this.Invoke(d, new object[] { texto });
           }
           else
           {
               lb_visualizacionMatricula.Text = texto;
               int x = groupBoxVisualizacion.Width + label29.Width;
               int w = lb_visualizacionMatricula.Width;
               lb_visualizacionMatricula.Left = x / 2 - w / 2;
           }
       }



A y otra cosa ¿Cómo podría pasar los distintos parámetros al método InsertarFila en el método work?

Código (csharp) [Seleccionar]

public void InsertarFilaDescarga(String modelo,
                                       String calidad,
                                       String color,
                                       String talla,
                                       String TotalTeorica,
                                       String TotalReal,
                                       String lote)
       {
           //Creamos fila;
           DataGridViewRow row = new DataGridViewRow();
           DataGridViewButtonColumn buttonColumn = new DataGridViewButtonColumn();
           buttonColumn.UseColumnTextForButtonValue = true;

           row.Cells.Add(new DataGridViewTextBoxCell { Value = modelo });
           row.Cells.Add(new DataGridViewTextBoxCell { Value = calidad});
           row.Cells.Add(new DataGridViewTextBoxCell { Value = color });
           row.Cells.Add(new DataGridViewTextBoxCell { Value = talla });

           if (lote.Equals("x1"))
           {
               row.Cells.Add(new DataGridViewButtonCell { Value = "x1" });
           }
           else if (lote.Equals("x2"))
           {
               row.Cells.Add(new DataGridViewButtonCell { Value = "x2" });
           }
           else
           {
               row.Cells.Add(new DataGridViewTextBoxCell { Value = "" });
               //dGV_Descarga.Rows.Add(new object[] { modelo,  calidad, color, talla,
               //    null,TotalTeorica,TotalReal});

               //var cell = dGV_Descarga.Rows[dGV_Descarga.RowCount - 1].Cells[4] = new DataGridViewTextBoxCell();
               //cell.Value = "";
               //cell.ReadOnly = true;
           }

           row.Cells.Add(new DataGridViewTextBoxCell { Value = TotalTeorica });
           row.Cells.Add(new DataGridViewTextBoxCell { Value = TotalReal });

           //insertamos fila
           if (dGV_Descarga.InvokeRequired)
           {
                dGV_Descarga.Invoke(() => dGV_Descarga.Rows.Add(row));
           }
           else
           {
               dGV_Descarga.Rows.Add(row);
           }
       }
       
       public void InsertarFilaDescarga(DataGridView dg , DataGridViewRow row)
       {
           if (dg.InvokeRequired)
           {
               
                dg.Invoke(() => dg.Rows.Add(row));
         
           }
           else
           {
               dg.Rows.Add(row);
           }
       }


kondrag_X1

al final lo conseguí mañana lo comentaré y pondré el código.

Eleкtro

Mi manejo en C# no es muy bueno.

Puedes declarar el delegado:
Código (csharp) [Seleccionar]
internal delegate void UpdateVisualizacionMatriculaDelegate(string texto);

private void updateVisualizacionMatricula()
{
if (this.InvokeRequired) {
this.Invoke(new UpdateVisualizacionMatriculaDelegate(updateVisualizacionMatricula), texto);

} else {
lb_visualizacionMatricula.Text = texto;
int x = groupBoxVisualizacion.Width + label29.Width;
int w = lb_visualizacionMatricula.Width;
lb_visualizacionMatricula.Left = x / 2 - w / 2;
}
}

//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================


O también puedes usar el delegado Action para evitar la declaración de delegados adicionales en el código

Código (csharp) [Seleccionar]
this.Invoke(new Action<string>(updateVisualizacionMatricula), texto)