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.
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
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. –
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