2012-05-09 9 views
7

In precedenza ho posto una domanda sulle mie prestazioni di dataGridView a causa del fatto che havign per visualizzare una grande quantità di righe che vengono aggiunte in base a un flusso in entrata. Sono state fornite soluzioni multiple, una delle quali abilita la modalità virtuale. MSDN ha un articolo sull'argomento ma sembra più complicato di quello che mi serve in quanto utilizza un database e un campo modificabile. My DataGridView è solo per la visualizzazione e i dati che visualizzo sono inseriti in una lista.Modalità virtuale DataGridView con un elenco semplice come fonte

Dopo aver accettato una risposta, ho ricevuto questo collegamento: http://www.codeproject.com/Articles/23937/Paging-Data-with-DataGridView-in-VirtualMode. Anche se utilizza un esempio di database, è più adatto a ciò di cui ho bisogno. La mia lista che conterrà i dati che voglio da visualizzare è dichiarato come segue:

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

Un ResultRow oggetto è definito come segue:

/* 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. */ 

}

Di seguito l'articolo di cui sopra, i creato un ResultRowCache. L'oggetto è composto come segue:..

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

Sul mio evento Form Load faccio la seguente (relative a questo problema che ho anche aggiunto un gestore di eventi, anche se questo è fatto utilizzando l'IDE in modo non direttamente che mostra in questo codice Definizione sotto!)):

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 che mi chiedo è come viene avviato il RowCount qui. Probabilmente è 0 (a causa della chiamata del costruttore di ResultRowCache (vedi sotto)) ma non sembra mai essere cambiato di nuovo. Questo incarico conta come riferimento? Come funziona itupdate?

In ogni caso, poi con quello che ho, il ResultRowCache è definito come segue:

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; 
    } 
    } 
} 

Infine, il mio evento CellValueNeeded per il datagrid è definito come segue:

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 */ 
    } 
} 

Il problema: il mio datagrid rimane vuoto anche se l'elenco "captureResults" viene riempito. Ecco cosa ho provato fino ad ora:

  • Aggiornare il membro RowCount del datagrid dopo lo switch nell'evento.
  • Dichiarare l'elenco con la quantità totale di risultati all'interno della cache per assicurarsi che sia sempre aggiornato. (Avevo paura che "modifiche esterne" non passassero alla Lista passata nel costruttore cache anche se era un riferimento. (Abbastanza nuovo con C#))
  • Imposta il RowCount del datagrid su 100 (valore fisso) nell'evento di caricamento del modulo.
  • Aggiunta una chiamata "Aggiorna()" al datagrid dopo aver aggiunto qualcosa all'elenco di captureResults. (questo accade da una discussione speciale che richiama una funzione che aggiunge qualcosa all'elenco)

Nessuna delle precedenti ha modificato nulla. La griglia rimane vuota. Penso che mi manchi qualcosa di abbastanza ovvio qui. Eventuali suggerimenti?

-edit- Aggiunto qualcosa Ho provato a farlo funzionare.

risposta

2

Ritengo che l'uso di Cache stia in qualche modo complicando il processo (anche se mi sento responsabile dopo aver inviato il link a msdn che implementa in questo modo).

Quello che mi sento di raccomandare come punto di partenza è:

  1. buttare via la cache (questo può essere utile in seguito se si esegue in problemi di memoria, ma per ora lascia solo ottiene il popolamento datagrid)

  2. Memorizza List<ResultsRow> in una variabile di istanza.

  3. Assicurarsi che dataGrid.VirtualMode = true; (o equivilant)

  4. implementare CellValueNeeded come segue:

    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: è necessario esporre alcune proprietà pubbliche supplementari in DataObject in modo che possano essere imposta come valori nel metodo.

Guarda come te la cavi. Se si impostano alcuni punti di interruzione all'interno del metodo CellValueNeeded che dovrebbero aiutare a eseguire il debug di qualsiasi ulteriore comportamento imprevisto. In bocca al lupo.

+0

Sono riuscito a farlo funzionare (senza cache) aggiornando il RowCount dopo ogni aggiunta con la dimensione della mia lista. Le prestazioni sembrano peggiorare comunque. (Forse perché sto aggiornando il modulo ogni aggiunta, invece di ogni ms da un addetto al background) La mia applicazione si congela anche relativamente velocemente dopo l'elaborazione dei dati. È un'implementazione errata della modalità virtuale o il problema si trova altrove? (per qualche motivo disegnare le righe (che possono avere diversi colori di sfondo) è molto difficile per questo sistema.Il mio laptop (che è più potente) può farlo più facilmente – Arnold4107176

+0

Come mai stai aggiornando il RowCount dopo ogni aggiunta? Condivido questo codice, poiché non sono sicuro di come funzioni, e non suona abbastanza bene.Se assegni il tuo Elenco a un bindingSource, che viene quindi assegnato a Grid.DataSource, i rowCounts e gli elenchi interni dovrebbero essere tracciati a sufficienza. –

+0

Ah, penso che questo sia il risultato della mia mancanza di comprensione del concetto: non ho impostato un'origine dati per il mio DataGridView quando ho abilitato la modalità virtuale perché pensavo che questo fosse il problema delle prestazioni. è che ho impostato la proprietà VirtualMode su true e definito l'evento CellValueNeeded. È corretto? Non capisco perché questo toglie l'impatto sulle prestazioni che otterresti altrimenti. t l'implementazione predefinita dell'evento che è così inefficiente per i set di grandi dimensioni? Sovrascriverlo con la modalità virtuale disattivata probabilmente non funzionerà, dovrò leggere. – Arnold4107176

Problemi correlati