I have an ultragrid who's DataSource property is set to a BindingList. I'm using MVP in such a way that binding to models is the only way of communication between the view and presenter.
My app usually uses about 45-60MB of RAM. When stress testing by pulling back 50,000 rows from a database and adding them to the BindingList (one at a time since there is no AddRange on a BindingList), it causes the memory usage to fly up to 600MB - 1GB+ within a matter of seconds and then crashes with a System.OutOfMemory exception.
I thought it was due to the fact that each row has a image depending upon a value on that row. I changed all such usage of .Appearance to reuse Appearance objects I added to the Appearances collection when creating the grid, but the problem persists. I also changed to using GetCellValue instead of referencing cells.
I finally tracked it down to the fact that I call e.Row.RefreshSortPosition in InitializeRow. When I uncomment this line it only uses about 288MB of RAM. Higher than I'd like, but understandable for the ridiculous amount of data it's showing. (Ideally we need to get the user to filter better when pulling the data, but I wanted to test this scenario anyway...)
I do have columns added to the .SortedColumns to sort by, but (I may be mistaken) it seemed like rows added after the initial load (we push updates out to the client every so often) would not end up in the correct position. So I make that call to ensure that when I call BindingList.Add(item), it ends up in the right spot.
Any thoughts on why this may be happening?(I can try to create a minimal solution to re-create the issue, but didn't want to do it, if it there was a simple "just do this instead" kind of answer. I'm using v10.3.)
Hi,
I'm not sure, but my best guess is that you are calling RefreshSortPosition while the grid is in the middle of processing the rows and this is causing some recursion. For example, if the grid is already in the process of loading an initializing all of the rows, and you call RefreshSortPosition on a row inside InitializeRow, this might cause all of the rows to be re-initialized again - the whole process starts over.
Like I said, that's just a guess.
I'm not sure calling RefreshSortPosition inside of InitializeRow is a good idea in any case. It's probably best to do it outside of the events of the grid and to just call this method after you add the rows.
You are correct that the grid doesn't automatically sort new rows that are added to it after the sorting has already completed. But if you are adding 50,000 rows to your data source at once, then refreshing the sort position of each individual row one at a time inside of InitializeRow is a very inefficient way to handle it. You would be much better off waiting until all 50,000 rows are loaded and then calling band.SortedColumns.RefreshSort once.
I am having the same problem and after reading this I moved the calls to RefreshSortPosition out of InitializeRow and call it after the row has been added/refreshed instead. However, I am still having the same problem. My situation is slightly more complex (which may or may not be relevant) because I have 1000s of rows in the grid where every 4 rows have several key cells merged (using the MergeCells feature - with MergedCellStyle set to Always) and a customized sort on one of the non-key cells such that the 4 rows are always sorted together (and therefore merged). Real time updates are broadcast to the grid which may result in the placement of the 4 rows (due to the customized sort) to be changed. Hence after resetting the 4 rows, so that their data is refreshed (and InitializeRow is called), I then call RefreshSortPosition on each of the 4 rows. At this point I periodically get an OutOfMemory exception.
System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
at System.Collections.Hashtable..ctor(Int32 capacity, Single loadFactor) at Infragistics.Win.UltraWinGrid.RowsCollection.RowsSortComparer..ctor(RowsCollection rows, Boolean groupingRows) at Infragistics.Win.UltraWinGrid.RowsCollection.MoveRowToCorrectSortOrder(UltraGridRow row) at Infragistics.Win.UltraWinGrid.RowsCollection.EnsureCorrectSortPosition(UltraGridRow row) at Infragistics.Win.UltraWinGrid.UltraGridRow.RefreshSortPosition()
Any ideas?
I am using v10.3
thanks
As long as your SortComparer isn't calling itself recursively, or doing something that might cause the grid to re-sort itself, I don't think that's an issue. And cell merging certainly shouldn't have any effect on sorting.
It's really impossible to guess what's happening here without being able to see it in action. Can you reproduce this issue in a small sample project and post it here so we can check it out?
ok thanks for the reply. There does not appear to be any recursive nature to the SortComparer. However, it has occurred to me that if RefreshSortPosition is called often in quick succession (e.g. due to a large number of real time updates) then presumably it would have to generate a large number of UltraGridCell objects in order to execute the Compare function. Do you think this could be the source of the problem (as opposed to the recursion itself being the source of the issue)?
I will see if I can produce a small sample program.
No, I don't see how cells could have anything to do with it. The cells are created when they are needed. The grid doesn't need to force the cell to be created in order to sort - it gets the value from the row.
The RefreshSortPosition method is not intended to be used a lot, though. The purpose of this method is to allow you to re-sort a single row whose value has change in a grid where all of the other rows are already in the correct order. It's an optimization so that you can put a single row into the correct spot instead of sorting the entire rows collection.
If you are making changes to more than one row, then calling RefreshSortPosition is not a good method to use. You would be better off calling Refresh on the SortedColumns collection to re-sort everything at once.