I'm using an UltraWinGrid to display messages coming in at regular intervals. The message structure is defined in a config file read at run time, and my program adds columns to the UltraWinGrid as needed to display strings, numbers, and booleans.
Because of the fluid structure of the data, I can't use any kind of binding to a collection of objects - the object structure would have to change on the fly. Instead I add/lookup rows to an UltraDataSource and iterate over each cell to update the values inside.
Even though the number of rows and the data in them mostly stay the same, every time my update method runs the vertical scroll position on the grid is reset to the top. I tried storing the ActiveRowScrollRegion.ScrollPosition, but even at the end of my method the value appears to be unchanged - the change to scroll position must be an asynchronous action.
I also captured the AfterRowRegionScrollChange event, but it only gets called when I manually move the scroll bar, not when the scroll bar is just bouncing to the top of the grid.
Any suggestions or thoughts?
Hello John,
Thank you for contacting Infragistics.
The UltraGrid should maintain its scroll position when you add or update rows, as long as you don't change the value of the DataSource property of the grid.
If you can provide me with a sample project that reproduces the issue, I'll look at it and see why it's not behaving as it should.
The grid's scroll position will be lost any time the layout gets reset. This will happen if you set the grid's DataSource / DataMember (or call SetDataBinding).
It can also happen if your DataSource sends a Reset notification.
If can also occur if, for some reason, the BindingManager sets the Current position to the first row.
So something you are doing in your code is almost-certainly causing one of these things to happen.
The scroll position is probably getting updated the next time the grid paints. So you could, in theory, store the position before you begin your operation, and then restore it inside the grid's Paint event. But this is a little tricky. You only want to do it when you have a stored position. And you need to prevent recursion, since setting the position will likely cause the Paint event to fire again.
My advice would be to try to find out what you are doing that is causing this to occur and stop doing it. That will be a much more reliable fix.
I confirmed that I wasn't setting either the DataSource or DataMemeber again after initialization.
I'm not sure if there's a way to detect when the DataSource sends a reset notification. The best I could do was inherit from DataSource and override Reset(), but it never got called so I'm pretty sure you're not talking about that method.
I don't know of anything in the code that would explicitly have reset the scroll position.
I followed your suggestion about handling the Paint event, and I think I have that working to an extent. It causes some flickering on the grid on updates, but it's preferable to what I had before. I'm going to mark this as an answer for now. In the future I may just try rewriting this process from scratch and see if I can isolate the exact problem. Thanks for your help.
Well, that's odd. Maybe it's not a Reset after all, but just the CurrencyManager positioning to the first row for some reason.
Try setting SyncWithCurrencyManager on the grid to false. You would do this once, maybe at design-time or in the Form_Load or Main method.
If that works, it might be a good solution. The only down side of this is if your code is depending on the CurrencyManager.Current to be in synch with the grid, it won't work any more. This is unlikely, though, unless you are binding other control on the form to the same data source and you need them to stay on the same record the grid is on.
If that still doesn't work, then I'm out of ideas. Like I said, if you can post a sample demonstrating the issue so I can reproduce it here, I'm sure I could track it down, but I understand if you feel like the workaround is good enough and don't want to keep pursuing it. :)
Gave that a shot, but no dice. InitializeLayout is not getting hit when the grid gets an update. Thanks though.
I'm not sure if this will work, but you could try putting a breakpoint into InitializeLayout and see if it is getting hit, and if so, the call stack might trace back to the Reset. The grid might handle this asynchronously, though, so this might not work.