Hi,
I use a wingrid which auto refreshes every 5 seconds.The problem that I face is when the user scrolls down the grid, suddenly the grid refreshes and moves back up to the top.I want the grid to stay in the same scroll area after refreshing.I set the the first row as active row after every refresh.
So how to save the current scroll position and load the same back after refresh?Or can anyone suggest a better solution?
Thanks,
Abja
I used this in the past after refreshing...
grid.Rows.ScrollCardIntoView(grid.ActiveRow);
This takes a row that it scrolls into view you'll need to know where you are in the grid as your setting you active row to the first...
You are going to lose more than just the scroll position. If you are resetting your data source, you will lose all state information in the grid. This includes row height, expanded state, column widths, selected rows, etc.
So you are probably better off not resetting the data source if you can avoid it.
The above line of code will only work in CardView, so that's probably not the right way to do. What you want is the FirstRow property on the ActiveRowScrollRegion. You can set this to the row you want at the top.
However, you can't store the row you had before the reset and then use the same row to restore the position, because the rows will all be destroyed and a whole new set of rows created. So the row you store won't be in the grid any more after the reset takes place. You will have to store some kind of key information about the row and then find that row again.
The only thing I want in fact is to have the same screen after the users click refresh (or an automatic refresh). Refresh = reload the datasource.
If a groupbyrow was the first displayed row, than that groupbyrow should be the first row to display after the refresh. If it's a datarow, then it should be that datarow. I don't think I'm the only one requiring that behaviour. Nothing more frustrating for the user to have to scroll back to where he was before the refresh, after each refresh.
For the groupbyrow, I use the description but I split the string to not include the '( 3 items)' when comparing after the refresh, because indeed, after a refresh it could be different. But I can try working with a Column and Value combination too, that's not the issue I think.
I just need to know how to keep the same row (groupedby or not) on the visible top after a refresh than it was before the refresh. How would you implement that?
Well, what I would probably do is avoid resetting the data source, if possible. Whenever the DataSource sends a reset notification to the grid, or when the grid's DataSource property is set, the grid has to throw away everything and start over. So the ideal solution would be to avoid doing those things. I realize, of course, that this is not always possible.
Barring that, I think what you are doing is correct. You would need to store some kind of Key information about the first visible row and then find that row and set it back after the reset occurs.
Where I am getting lost here is in what exactly is not working any why. Other than the fact that a GroupByRow can't use cell values as key information, there's really no difference between a GroupByRow and a regular row. Using the Value and Column as a key should work.
One reason I can think of why this might not work is because the grouping may be done lazily. In which case, when you looped through the grid rows after the reset, you would not be able to find the GroupByRow. I don't think that's the issue here, though, because if it were, it would be immediately obvious to you that your code was simply never finding the GroupByRow that it saved.
Another reason this may not work is because once the grid is grouped, the rows are in a hierarchy. So if the first row in the grid happens to be a child row, then looping through grid.Rows will not find that row. To get around this, you would use one of the methods on the Rows collection that gets all of the childs rows in addition to the parent rows, like GetRowsEnumerator. But once again, if the row were not found at all, this would be immediately obvious to you, so I don't think that's the issue, either.
I can't avoid refreshing the data, it is a requirement to have fresh data each x seconds.
When rows are not grouped by it works, when rows are grouped by and it's a datarow as first row it also works. But when rows are grouped by and the firstrow is Grouped By row it doesn't, the grid is displayed with the first row of the grid on top (<> The first row displayed).
The correct row is found (I seperate the description with "(" seperator to be shure that the number of items (datarows) doesn't change the fact that that groupedbyrow is the first one, like this :
if (FirstRowDescription != string.Empty) { char[] seperators = { '(' }; if (row.Description.Split(seperators)[0] == FirstRowDescription.Split(seperators)[0]) { ok = true; } }
The correct row is found and stored:
if (CheckIfRowIsFirstRow(row, pkValuesFirstRow)) { this.DisplayLayout.RowScrollRegions[0].FirstRow = row; FirstRow = row; setFirstRow = true; DoSearch = false; }
Here this.DisplayLayout.RowScrollRegions[0].FirstRow has the correct row!
This method is called in the ctlTaskDataGrid.cs that inherits from UltraGrid.
I added a Property FirstRow in the ctlTaskDataGrid.cs to store the FirstRow and set it later in the forms using the ctlTaskDataGrid control.
Then in the LoadData Method on the Form using the ctlTaskDataGrid.cs control (named ugvShipmentMovements in this case) I do this:
Somewhere the ugvShipmentMovements.DisplayLayout.RowScrollRegions[0].FirstRow was reseted and I can't find where or why. But the most strange behaviour is when I force the ugvShipmentMovements.DisplayLayout.RowScrollRegions[0].FirstRow = ugvShipmentMovements.FirsRow (this is the property I made on the ctlTaskGrid.cs) it doesn't do anything at all:
This is getting very frustrating.. Any help is more than welcome!
First I thought it had something to do with the inheritance somehow, but then why does it works fine with a datarow? It's the exact same way of setting it, only then ugvShipmentMovements.DisplayLayout.RowScrollRegions[0].FirstRow doesn't get resetted.
Okay, so it's pretty clear to me that this is a timing issue of some kind. You are setting the FirstRow on the grid and it's getting reset by something that happens after the LoadData method is called.
Where is LoadData being called from?
Perhaps it would be better to move the line of code that sets the FirstRow on the RowScollRegion of the grid to some later point, such as in the InitializeLayout event of the grid.
If that's no good, then another option would be to create a separate method that sets the FirstRow and instead of calling the method directly from LoadData, you use a BeginInvoke to call it. That will create a delay that might solve the issue.
I don't know quite yet if it's a time issue. The weird thing is that it works for datarows and not for groupbyrows.
I call the LoadData fucntion at several locations on the frmShipmentMovement Form, the refresh button click, the applyfilter method ... each time the data needs to be fresh.
The InitializeLayout Method is called before the LoadData Method when I debug.
About the BeginInvoke, I don't knwo how to implement this. Isn't that used for assynchronously calls and multithreading? Don't know for sure this is a good idea.
I'm not sure it's a good idea to call BeginInvoke on the delegate. You should probably be calling BeginInvoke on the grid or the form and passing in the delegate.
But if that didn't work, then it's most likely a moot point, anyway.
AndyCaignie said: That is something I don't understand. It would be something like this: int i = 0; int j = 5; i = j; and when you set a Watch on i it would still be 0 instead of 5, this is what happens with the DisplayLayout.RowScrollRegions[0].FirstRow property. It's not logical.
That is something I don't understand.
It would be something like this:
int i = 0;
int j = 5;
i = j;
and when you set a Watch on i it would still be 0 instead of 5, this is what happens with the DisplayLayout.RowScrollRegions[0].FirstRow property. It's not logical.
I'm not sure why this is happening. As I said above, my theory is that it's because the grouping has not completed yet or the FirstRow is getting changed again at some point after you said it, but I'm only guessing here, since I can't see the behavior.
Perhaps at this point, you should try to create a small sample project that demonstrates the problem and either post it here or Submit an incident to Infragistics Developer Support so we can check it out.
Ok, I successfuly managed to implement a delegate to a SetFirstRow Method. After the LoadData method I call this method through the delegate.BeginInvoke(null, null). This calls my SetFirstRow method, I checked this. But the FirstRow is still not changed.
I think it's something to do with the fact that you can't set a groupedbyrow as FirstRow or something like that. I have the Correct row stored, I set it:
not set to correct row <- ugvShipmentMovements.DisplayLayout.RowScrollRegions[0].FirstRow = ugvShipmentMovements.FirstRow; -> correct row
AndyCaignie said:I don't know quite yet if it's a time issue. The weird thing is that it works for datarows and not for groupbyrows.
This makes perfect sense as a timing issue. If the grid is not grouped, the rows are there. If it's grouped, the grouping is done asynchronously.
AndyCaignie said:About the BeginInvoke, I don't knwo how to implement this. Isn't that used for assynchronously calls and multithreading? Don't know for sure this is a good idea.
BeginInvoke is usually used to marshal across threads, but you can call it on the same thread. You just create a method that does what you need to do, then create a delegate to that method and call BeginInvoke with that delegate.
Do a search on this forum for BeginInvoke, I'm sure there are some sample code snippets posted.