Reputation: 219
I have got a DataTable bound to a DataGridView. The DataTable is filled with max 30000 rows. The DataGridView should show the content of the DataTable while it is filled, which can take up to 3 minutes, because of some calculation process.
Every Row contains text-cells and two image cells. In the beginning i was loading all images directly to the DataTable, but at some point (~10000 rows) the programm crashed, because the system was out of memory. So i adapted my code a bit. The problem was, that the images are consuming a lot of memory. Now i only load images which can be seen by the user. This helps a lot and the system does not crash anymore loading 30000 rows.
The problem only occures while scrolling heavily through the rows. I set images using the piece of code provided by Alireza Maddah:
public void GetVisibleCells(DataGridView dgv)
{´
ClearImages()
var vivibleRowsCount = dgv.DisplayedRowCount(true);
var firstDisplayedRowIndex = dgv.FirstDisplayedCell.RowIndex;
var lastvibileRowIndex = (firstDisplayedRowIndex + vivibleRowsCount) - 1;
for (int rowIndex = firstDisplayedRowIndex; rowIndex <= lastvibileRowIndex; rowIndex++)
{
var cells = dgv.Rows[rowIndex].Cells;
foreach (DataGridViewCell cell in cells)
{
if (cell.Displayed)
{
// This cell is visible...
// SET IMAGES TO ROW AND SAVE INDEX
}
}
}
}
How to find out which DataGridView rows are currently onscreen?
This piece of code is bound to the scrolling event. I set images if row is visible to the user and i save the index of the row to a list. Before setting the image i call ClearImages(). This function sets all rows which have images to null, using the index entries from list.
I think that setting the variables to null does not free the memory, but this was just my first thought. What do you think? Any ideas?
I can not use paging or virtual mode...
Upvotes: 0
Views: 1561
Reputation: 10401
Try to
private void ClearNotVisibleImages()
{
foreach(var row in this.GetNotVisibleDataRowsWithImages())
{
var cell = row["Image"];
Image image = (Image)(cell .Content);
cell.Content = null;
image.Dispose();
}
// If it will be really needed
GC.Collect();
// Improved Thanks @rentanadviser
GC.WaitForPendingFinalizers();
GC.Collect();
}
Upvotes: 1
Reputation: 4489
you should use DataGrid.AllowPaging Property to split content pages (e.g 100 images per page) this prevents out of memory exception. You can try to dispose old visible cell images, also see GC.Collect() not collecting immediately?
Upvotes: 2
Reputation: 1401
Make sure the images are not linked by anything. You can also call GC.Collect()
after clearing the images to clean up the large object heap. However, that will slow down the responsiveness. Also, I would check first which images are not longer visible and clear only those instead all of them.
Upvotes: 0