2012-05-09 7 views
7

Anteriormente, hice una pregunta sobre el rendimiento de mi dataGridView debido a que tenía que mostrar una gran cantidad de filas que se agregan en función de una transmisión entrante. Se dieron múltiples soluciones, una de ellas habilitando el modo virtual. MSDN tiene un artículo sobre el tema, pero se siente más complicado de lo que necesito, ya que utiliza una base de datos y un campo editable. My DataGridView solo se muestra y los datos que visualizo se colocan en una lista.Modo virtual de DataGridView con una lista simple como fuente

Después de aceptar una respuesta, recibí este enlace: http://www.codeproject.com/Articles/23937/Paging-Data-with-DataGridView-in-VirtualMode. Aunque eso utiliza un ejemplo de base de datos, es más adecuado para lo que necesito. Mi lista que contendrá los datos que yo quiero mostrar está declarada como sigue:

List<ResultRow> captureResults = new List<ResultRow>(); 
objeto

Un ResultRow se define como sigue:

/* Simplified */ 
public class ResultRow 
{ 
    private int first = 0; 
    private string second = ""; 
    private UInt64 third = 0; 
    private IPAddress fourth = null; 
    /* etc */ 

    public ResultRow() 
    { 
    } 

    public void Set (<the values>) //In actuallity a KeyValuePair 
    { 
     //field gets set here 
    } 

    public UInt64 Third 
    { 
     get { return third; } 
     set { third = value; } 
    } 

    /* etc. */ 

}

Tras el artículo mencionado anteriormente, i creó un ResultRowCache. El objeto se hace de la siguiente manera:..

/* Page size set to 100. */ 
ResultRowCache _cache = new ResultRowCache(PAGE_SIZE, captureResults); 

En mi evento Load del formulario hago lo siguiente (en relación con este problema también agregué un controlador de eventos a pesar de que se han hecho utilizando el IDE de modo que no estén directamente mostrando en este código Definición a continuación!)):

dataGrid.VirtualMode = true; 

_cache = new ResultRowCache(PAGE_SIZE, captureResults); 

dataGrid.Columns.Add("FirstColumn" , "First column header"); 
dataGrid.Columns.Add("Second Column", "Second column header"); 
/* Etc. Adding all columns. (Every member or ResultRow has it's own column. */ 

dataGrid.RowCount = (int)_cache.TotalCount; 

Una cosa que me pregunto es cómo se inicializa el RowCount aquí. Probablemente sea 0 (debido a la llamada al constructor de ResultRowCache (ver a continuación)) pero parece que nunca más se cambiará. ¿Esta tarea cuenta como referencia? ¿Cómo se actualiza?

De todos modos, en adelante con lo que tengo, la ResultRowCache se define como sigue:

public class ResultRowCache 
{ 
    public int PageSize = 100; 
    public long TotalCount; 
    public List<ResultRow> CachedData = null; 
    private List<ResultRow> FullData; 

    int _lastRowIndex = -1; 

    public ResultRowCache (int pageSize, List<ResultRow> total) 
    { 
     PageSize = pageSize; 
     FullData = total; 

     LoadPage(0); 
    } 

    public void LoadPage (int rowIndex) 
    { 
     int lastRowIndex = rowIndex - (rowIndex % PageSize); 

     /* Page already loaded */ 
     if(lastRowIndex == _lastRowIndex) return; 

     /* New page */ 
     _lastRowIndex = lastRowIndex; 

     /* Create a new cashes data object */ 
     if(CachedData == null) CachedData = new List<ResultRow>(); 

     /* If cached data already existed, clear */ 
     CachedData.Clear(); 

     /* The index is valid (there is data */ 
     if (lastRowIndex < FullData.Count) 
     { 
      /* Not a full page */ 
      if (lastRowIndex + PageSize > FullData.Count) 
      { 
       CachedData = FullData.GetRange(lastRowIndex, ((lastRowIndex + PageSize) - 1) - FullData.Count); 

      } 
      /* Full page */ 
      else 
      { 
       CachedData = FullData.GetRange(lastRowIndex, PageSize); 
      } 
     } 

     TotalCount = CachedData.Count; 
    } 
    } 
} 

Por último, mi evento CellValueNeeded para la cuadrícula de datos se define de la siguiente manera:

void DataGridCellValueNeededEvent(object sender, DataGridViewCellValueEventArgs e) 
{ 
    _cache.LoadPage(e.RowIndex); 

    int rowIndex = e.RowIndex % _cache.PageSize; 

    switch (dataGrid.Columns[e.ColumnIndex].Name) 
    { 
     /* Not actual names, example */ 
    case "FirstColumn": e.Value = _cache.CachedData[rowIndex].First; break; 
     case "SecondColumn": e.Value = _cache.CachedData[rowIndex].Second; break; 
     /* Rest of the possibly columns/ResultRow values */ 
    } 
} 

El problema: Mi datagrid permanece vacío aunque la lista "captureResults" se llena. Esto es lo que intenté hasta ahora:

  • Actualice el miembro RowCount de la cuadrícula de datos después del cambio en el evento.
  • Declare la lista con la cantidad total de resultados dentro de la memoria caché para asegurarse de que esté siempre actualizada. (Temía que las "modificaciones externas" no pasaran a la Lista que pasé en el constructor en caché aunque era una referencia. (Bastante nuevo con C#))
  • Establezca el RowCount de la cuadrícula de datos en 100 (valor difícil) en el evento de carga del formulario.
  • Agregó una llamada "Update()" a la cuadrícula de datos después de agregar algo a la lista captureResults. (Esto sucede a partir de un hilo especial que Invoke es una función que agrega algo a la lista)

Ninguno de los anteriores ha cambiado nada. La grilla permanece vacía Creo que me falta algo bastante obvio aquí. ¿Alguna sugerencia?

-edit- Agregué algo que intenté para que funcione.

Respuesta

2

Creo que el uso de Cache complica un poco el proceso (aunque me siento responsable después de enviarle el enlace al msdn que se implementa de esta manera).

Lo que yo recomendaría como punto de partida es:

  1. tirar la caché (esto puede ser útil más adelante si llegas a tener problemas de memoria, pero por ahora le acaba de obtener su poblamiento cuadrícula de datos)

  2. Almacene su List<ResultsRow> en una variable de instancia.

  3. Asegúrese de que dataGrid.VirtualMode = true; (o equivilant)

  4. Implementar CellValueNeeded de la siguiente manera:

    private void gridContacts_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) 
        { 
         ResultRow dataObject = resultRows[e.RowIndex]; 
    
         switch(e.ColumnIndex) 
         { 
          case 0: 
           e.Value = dataObject.First; 
           break; 
          case 1 : 
           e.Value = dataObject.Second; 
           break; 
          //etc.. 
         } 
        } 
    

Nota: necesitará para exponer algunas propiedades públicas adicionales en DataObject para que puedan ser establecer como valores en el método.

Mira cómo te va con eso. Si establece algunos puntos de interrupción dentro del método CellValueNeeded, esto debería ayudar a eliminar cualquier otro comportamiento inesperado. Buena suerte.

+0

Logré que funcionase (sin caché) actualizando el RowCount después de cada adición con el tamaño de mi lista. El rendimiento parece peor, sin embargo. (Tal vez porque estoy actualizando el formulario cada adición, en lugar de cada ms por un trabajador de segundo plano) Mi aplicación también se congela relativamente rápido después de procesar los datos. ¿Es una implementación incorrecta del modo virtual o el problema está en otra parte? (Por alguna razón, dibujar las filas (que pueden tener diferentes colores de fondo) es muy difícil para este sistema. Mi computadora portátil (que es más poderosa) puede hacerlo más fácilmente. – Arnold4107176

+0

¿Por qué está actualizando el RowCount después de cada adición? comparto este código, ya que no estoy seguro de cómo funciona eso, y no suena del todo bien. Si asigna su Lista a un bindingSource, que luego se asigna a Grid.DataSource, entonces los rowCounts y las listas internas deben rastrearse lo suficiente. –

+0

Ah, creo que este es el resultado de mi falta de comprensión sobre el concepto. No establecí un origen de datos para mi DataGridView cuando habilité el modo virtual, ya que asumí que este era el problema de rendimiento. Si mantengo eso en contacto, la única diferencia es que configuré la propiedad VirtualMode en true y definí el evento CellValueNeeded. ¿Es correcto? No entiendo muy bien por qué esto elimina el impacto en el rendimiento que de otro modo obtendría. t la implementación predeterminada del evento que es tan ineficiente para grandes conjuntos? Anularlo con el modo virtual desactivado probablemente no funcione, tendré que leer. – Arnold4107176

Cuestiones relacionadas