DataGridView-Leistung in Kombination mit einer BindingList datasource
Ich Baue eine Anwendung, die zur Anzeige von empfangenen Daten aus einem externen system. Diese Daten können sehr schnell, während die Menge von bytes jede Zeile nimmt, ist relativ klein. Dies bedeutet, dass eine Menge von Zeilen, die Hinzugefügt werden müssen, die pro Zeiteinheit. Ich bin derzeit an einem Punkt, wo es scheint, ich empfangen Sie Daten schneller, als ich verarbeiten kann was bedeutet meine Speicherauslastung steigt.
Ich denke, ein großer Teil dieser hat zu tun mit der Zeichnung der tatsächlichen dataGridView. Ich habe wenig getan, tweaks, um das dataGridView-in der Hoffnung, es würde die Leistung erhöhen bereits. (z.B. deaktivieren von " auto-Größe, Besondere Stile, etc.)
In eine neue Ergänzung, die ich Hinzugefügt Färbung der Zeilen, die erforderlich war. Derzeit meine Anwendung funktioniert wie folgt:
- Ich Daten aus dem externen system
- Stelle ich die Daten in eine Warteschlange (ConcurrencyQueue) von einem thread
- Einem anderen thread bezieht Daten aus, die queue, verarbeitet diese und fügt Sie zu der BindingList, dass der table gebunden ist.
Den tatsächlichen hinzufügen geschieht in einer Funktion mit 2 Parametern:
1. Eine Liste mit den Positionen für die Spalten (items)
2. Eine Farbe für die Zeile.(Farbe)
sieht es wie folgt aus (semi-pseudo):
/* Store the color for the row in the color list so it is accessible from the event */
rowColors.Add(rowColor); //Class variable that stored the colors of the rows used in the DataGridCellFormatting event
/* Create the row that is to be added. */
ResultRow resultRow = new ResultRow();
foreach(item in items)
{
resultRow.Set(item); /* It's actually a dictionary because some fields are optional, hence this instead of a direct constructor call) */
}
bindingList.Add(resultRow);
/* Row coloring based on error is done in the OnCellFormatting() */
/* Auto scroll down */
if (dataGrid.Rows.Count > 0)
{
dataGrid.FirstDisplayedScrollingRowIndex = dataGrid.Rows.Count - 1;
}
Wie man im obigen code die Farbe, die ich erhalten einer Liste Hinzugefügt, die in ein Ereignis des datagridview wie folgt:
void DataGridCellFormattingEvent(object sender, DataGridViewCellFormattingEventArgs e)
{
//done by column so it happens once per row
if (e.ColumnIndex == dataGrid.Columns["Errors"].Index)
{
dataGrid.Rows[e.RowIndex].DefaultCellStyle.BackColor = rowColors[e.RowIndex];
}
}
Die BindingList ist wie folgt definiert:
BindingList bindingList;
wo ResultRow ist eine Klasse mit einer Struktur wie dieser:
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. */
Sind es relativ einfache Dinge, die ich tun kann, um die Leistung zu erhöhen? Ich dachte eventuell deaktivieren Zeichnung des datagrid-während der Verarbeitung beschäftigt ist und ziehen, wenn es fertig ist. (obwohl nicht bevorzugt) eine Andere Sache ist ggf. aktualisiert weniger Häufig statt nach jedem Einzelteil. (BindingList scheint für die automatische Aktualisierung des DataGridView, wenn etwas Hinzugefügt wird, es aber)
Ich hoffe jemand ist bereit/in der Lage zu helfen.
-Bearbeiten-
Die Reaktionsfähigkeit der form wegen, ziemlich schlecht, wenn es die Verarbeitung von Daten in der zuvor beschriebenen Art und Weise, vor allem nach einiger Zeit. (auch wenn der obige Prozess findet in der backgroundworker-Klasse(N) und hintergrund-threads)
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ja, es gibt ein paar Dinge, die Sie tun könnten, um ihn zu beschleunigen.
Erstens - die Virtualisierung des datagrid. Das ist ein eingebauter Mechanismus, um die winforms-datagrid, dass nur Zeilen füllen, und malen Sie die client-region für dataitems, die sichtbar sind. Deshalb, wenn Ihr control ist und zeigt nur 20 Zeilen (und einer scrollbar für die anderen), dann nur 20 Elemente, die verarbeitet werden in das datagrid-Steuerelement als UI.
Wenn Sie dann scrollen Sie in der grid-Ansicht, um die anderen Elemente, die das datagrid aufgefüllt und zeigt die angeforderten Zeilen auf Nachfrage.
Es ist ein bisschen basteln, das Sie tun müssen, um diese (CellValueNeeded Veranstaltungen müssen abonniert werden) und können Sie Bearbeiten müssen Ihre bindingsource dataitems.
Sehen http://msdn.microsoft.com/en-us/library/ms171622.aspx für weitere Informationen.
Die zweite Sache, die Sie tun können, ist zu sperren der Benutzeroberfläche aus aktualisieren, während Sie füllen in einem 'Stück' Ihrer Daten.
Wie Sie bereits angedeutet, bindinglist wird automatisch aktualisieren Sie das raster, wenn Sie Elemente hinzufügen. Aber durch die Aussetzung der Benutzeroberfläche aus aktualisieren, dann neuaktivieren in einem bestimmten Intervall (z.B. jede Sekunde), wird das streaming von Daten auf einen weniger Konstanten rate.
Beachten Sie jedoch, dass die gleiche Verarbeitung wird noch getan werden müssen, für die Daten, so ist es unwahrscheinlich, dass dies vollständig zu lösen, Ihre Daten, und kann mehr effektiv bei der Reduzierung der Bildschirm flimmern.
Sehen
Control.SuspendLayout()
undControl.ResumeLayout()
für weitere Informationen.Meiner Meinung nach der Virtualisierung werden Ihre wirksamste Instrument, als dessen einziger Zweck ist die Verbesserung der grid-Funktionalität für sehr große Datenbestände.
Mag der performance-drop nach einiger Zeit wegen der schieren Anzahl der Zeilen im grid. Sollten Sie Virtuellen Modus versuchen.
Aber versuchen Sie zunächst, das zurückstellen des Gitters zu aktualisieren und neue Einträge hinzufügen in den Reihen, d.h. reduzieren Sie die update-Frequenz. Also, vor jedem batch-update:
Und danach:
Nach der letzten Zeile weiter scrollen bis zur letzten Zeile.