I am trying to change the color of a Row based on a value, which works perfectly. Except I need to change the row above this row as well, and this works on the first refresh of the grid, but subsequent refreshes it doesn't work because e.Row.Index is not the index but -1.
This is the code I am using:
Me.grd_Main.Rows(e.Row.Index - 1).Appearance.BackColor = cClosedControllerBlue
Any ideas why it works the first time and not subsequently?
Thanks
M
Hi M,
Is the Index actually -1? Or is the Index 0 and it comes out -1 when you subtract one from it. I can't see any reason why any row in the grid would ever return -1 for it's Index.
That is the crazy part, it is actually -1, I had to put a check in because it was crashing with a -2 once I subtracted 1.
I had to look in the documentation to try and figure out what a -1 meant, of course it doesnt exist. That's how I ended up here.
If I can reproduce it in a simpler sample project, would that be of value in figuring it out?
Thanks for following up on this, I greatly appreciate your help.
Hi Shaolin,
I tried this out and I get the same results. But we were never able to duplicate the issue before. As you can see, my last reply to this thread asked for a sample and then the customer never followed up.
Anyway, there are a number of factors at work here. This sample is loading the grid on-demand and it's calling ExpandAll in the form initialization, so my guess is that these rows are getting initialized before they are actually part of the grid's Rows collection and that's why they don't have a valid index.
This may or may not be a bug, but frankly, the Index of the row is not a very useful thing in most cases, anwyay. Row indices will change when you filter or sort the grid, so it's not something you can generally rely on for anything important.
The obvious workaround would be to simply check for -1 and then bail out of the InitializeRow event. Of course, it depend what you are using the event for and why you need the row index.
Hi Mike,
Thanks for your detailed explanation!
My grid is in virtual mode. I have a data source that is a list. I do sorting and filtering to my data source using work threads. The row of a row in the grid is mapped to the index of the record in my data source. I use the row index to get its data record and set the row level appearances based on the values of some record fields. For performance reasons, I try to stick with my data record instead of UltraGridRow. I always call Refresh(RefreshRow.FireInitializeRow, true) to Rows of my grid when I need to fresh data records in the data source to the grid, so my InitializeRow event handler is eventually called with a correct row index. My consider is the performance and would like to suppress these event calls for all rows with an index of -1. I have tens of thousands records and records in the data source and they are added and removed quite often.
I also noticed that IntinializeRow event was fired before any column data was requested:
InitializeRow - band: 0, row: -1InitializeRow - band: 1, row: -1InitializeRow - band: 1, row: -1InitializeRow - band: 1, row: -1InitializeRow - band: 1, row: -1InitializeRow - band: 1, row: -1InitializeRow - band: 0, row: -1
CellDataRequested - Band = RootBand; Row = 0; Column = ID; Data = 0; CellDataRequested - Band = RootBand; Row = 0; Column = Col0; Data = 459239609; CellDataRequested - Band = RootBand; Row = 0; Column = Col1; Data = 262; CellDataRequested - Band = RootBand; Row = 1; Column = ID; Data = 1; CellDataRequested - Band = RootBand; Row = 1; Column = Col0; Data = 1431531252; CellDataRequested - Band = RootBand; Row = 1; Column = Col1; Data = 263; CellDataRequested - Band = ChildBand; Row = 0; Column = ChildCol0; Data = 0.73772578441432; CellDataRequested - Band = ChildBand; Row = 0; Column = ChildCol1; Data = 31; CellDataRequested - Band = ChildBand; Row = 1; Column = ChildCol0; Data = 0.229192165298943; CellDataRequested - Band = ChildBand; Row = 1; Column = ChildCol1; Data = 32; CellDataRequested - Band = ChildBand; Row = 2; Column = ChildCol0; Data = 0.927423017065703; CellDataRequested - Band = ChildBand; Row = 2; Column = ChildCol1; Data = 33; CellDataRequested - Band = ChildBand; Row = 3; Column = ChildCol0; Data = 0.914841804613751; CellDataRequested - Band = ChildBand; Row = 3; Column = ChildCol1; Data = 34; CellDataRequested - Band = ChildBand; Row = 4; Column = ChildCol0; Data = 0.0830325270458276; CellDataRequested - Band = ChildBand; Row = 4; Column = ChildCol1; Data = 35;
How do we specify a row appearance efficiently base on data in that row?
Thanks,Shaolin
Regarding the Row index of -1, as I said, you can easily get around this by simply checking for -1 and then bailing out of the event. If you want to prevent the event from firing, then maybe the best thing to do would be not to hook the event until after the call to ExpandAll - since that's what's triggering the InitializeRow in this case.
Shaolin said:How do we specify a row appearance efficiently base on data in that row?
The best way to do this is to use the InitialieRow. If you are concerned about the efficiency, then I recommend that you check out the WinGrid Performance Guide. It discusses the best, most efficient way to apply appearances using the InitializeRow event.
I am sorry that I have to come back to this question.
Mike Saltzman said:It discusses the best, most efficient way to apply appearances using the InitializeRow event.
How can I use the InitializeRow event with a Row object of -1 index? For example, the background color is set to Red if the value in Price column is negative and Green for a positive value.
I am working with multiple bands now. After a parent row is expanded, the InitializeRow event is fired only once for all child rows with -1 index. There is no way for me to setup a row appearance based on the column values of the row.
Could you please shed some more light on this issue?
I don't understand your question.
If you want to base the color of the row or cell on a value in a cell of that row, what does the index of the row have to do with it? You don't need a row index to access a value in a cell. You simply use:
e.Row.Cells[columnName].Value
I can't think of any reason why the Index of the UltraDataRow would change... unless you inserted or deleted a row. In which case, every row below that row would have it's index modified.
You are correct that sorting the grid only sorts the grid rows and doesn't affect the DataSource.
Yes, I meant to say "get hold of the UltraDataRow". Will the index of a UltraDataRow get changed in its life time? If not, this index will be the index of my record in my data list. My assumption is that the index of UltraGridRow gets changed because of sorting but nothing will affect UltraDataRow's index in its life time. In my applications, UltraGrid sorting is disabled, so the index of a UltraGridRow should eventually be same as UltraDataRow. Could you please correct me if my assumption is wrong?
Thanks so much,Shaolin
This is such a complex scenario and there's so much going on that I am having a hard time figuring out how to assist you with this.
Does the InitializeRow event on the grid fire again at some point after the data has been populated into the data Source? If so, then all you have to do is ignore the InitializeRow when the Index is -1 and when it fire again later, it will work fine.
If not, then there are two ways I think we can approach this. One is for you to try to work around the issue and prevent the InitializeRow from being called before the data is populated. As I recall, you pointed out how to duplicate this behavior using one of our samples, but the problem depends on a number of very specific things happening in order. For example, the problem only occurs when you call ExpandAll on the grid's Rows collection before it has painted the first time. So one potential workaround would be to defer the ExpandAll until after the grid paints. You could easily do this by hooking the Paint event of the grid. The first time it fires, you call ExpandAll and then unhook the event.
If that doesn't help, there may be other ways to work around the issue.
If none of that helps, then I could write this up as a bug for our developers to look into and see if the current behavior is correct or not, and if not, see what we can do about fixing it.
Shaolin said:Is there an easy way for me to get hold of the UltraGridRow by using the UltraGridRow object?
This question doesn't make sense, but I assume you meant to say "get hold of the UltraDataRow". The answer is yes - you can get use the UltraGridRow.ListObject property to get the underlying data object from the data source, which in this case will be an UltraDataRow. I'm not sure how that helps you, though.
The InitializeRow event is fired before any cell data is requested by UltraDataSource. My grid is in virtual mode.
Shaolin said: I also noticed that IntinializeRow event was fired before any column data was requested: InitializeRow - band: 0, row: -1InitializeRow - band: 1, row: -1InitializeRow - band: 1, row: -1InitializeRow - band: 1, row: -1InitializeRow - band: 1, row: -1InitializeRow - band: 1, row: -1InitializeRow - band: 0, row: -1 CellDataRequested - Band = RootBand; Row = 0; Column = ID; Data = 0; CellDataRequested - Band = RootBand; Row = 0; Column = Col0; Data = 459239609; CellDataRequested - Band = RootBand; Row = 0; Column = Col1; Data = 262; CellDataRequested - Band = RootBand; Row = 1; Column = ID; Data = 1; CellDataRequested - Band = RootBand; Row = 1; Column = Col0; Data = 1431531252; CellDataRequested - Band = RootBand; Row = 1; Column = Col1; Data = 263; CellDataRequested - Band = ChildBand; Row = 0; Column = ChildCol0; Data = 0.73772578441432; CellDataRequested - Band = ChildBand; Row = 0; Column = ChildCol1; Data = 31; CellDataRequested - Band = ChildBand; Row = 1; Column = ChildCol0; Data = 0.229192165298943; CellDataRequested - Band = ChildBand; Row = 1; Column = ChildCol1; Data = 32; CellDataRequested - Band = ChildBand; Row = 2; Column = ChildCol0; Data = 0.927423017065703; CellDataRequested - Band = ChildBand; Row = 2; Column = ChildCol1; Data = 33; CellDataRequested - Band = ChildBand; Row = 3; Column = ChildCol0; Data = 0.914841804613751; CellDataRequested - Band = ChildBand; Row = 3; Column = ChildCol1; Data = 34; CellDataRequested - Band = ChildBand; Row = 4; Column = ChildCol0; Data = 0.0830325270458276; CellDataRequested - Band = ChildBand; Row = 4; Column = ChildCol1; Data = 35;
I have my data records which are filtered and sorted in my own data source. My UltraGrid is just a window to display a portion of my data. I am trying not to use row.Cells for performance reason.
Each UltraGridRow must be mapped to a UltraDataRow. Even the index of the UltraGridRow is -1 but the corresponding UltraDataRow must have a valid index. Is there an easy way for me to get hold of the UltraGridRow by using the UltraGridRow object? This row index is important to me because it is also the index in my own data source list.