Hi,
Within a WinForms UlraGrid, I am looking for a means (via code) to alter the appearance of an entire row, whenever a targeted column value meets a certain condition. For example, I already know that I can target the respect cell via the ConditionValueAppearance. The closest I could find to what might work is the ConditionAppearanceRow Class. Unfortunately you don't provide any code snippets to demonstrate how this class is hooked up with a given DisplayLayout Band.
In any case, I need this capability through code, so I can set the row appearance on the fly. If there is another way to do this, I am all ears.
Thanks,
Lacy
Hi Lacy,
Conditional Appearances are really useful for setting things up at Design-time. But at run-time, they actually require more code than neccessary and it's much easier to do things a different way.
I recommend using the InitializeRow event of the grid. This event is specifically designed to help you with situations just like this one where you want to color the row based on a value inside that row. All you do is handle the event, examine the row and it's cells and then set the Appearance properties on the row to suit your needs.
Hi Mike,
I implemented a conditional appearance in my initialize row event (changes backcolor based on value), but now I am seeing a slower response time when I change the rowfilter on the dataview the ultragrid is bound to. Do you have any performance tips?
Thanks,Kelly
Well, one inefficient thing I notice here is that by using the enumerator on the Cells collection, you are forcing the creation of every cell in the grid. You should try to avoid creating cells you don't need.You can improve the performance a little and the memory usage a lot, but looping through the columns instead of the cells.
You can do something like RowName.Band.Columns to get the columns collection.
You could do the same check you are already doing on the column key. But when you want to check the Value of the cell, use RowName.GetCellValue and pass in the column. This allows you to get the cell value without creating the cell object.
Now... when you apply an Appearance to the cell, you have to create the cell, anyway. So the above will not be very helpful until you also eliminate some cells. Since you are applying one of three colors to every cell, you may want to set the CellAppearance on the column to the color that is most commonly used. That way you only have to create cells when using one of the other two colors.
Also, by referencing the MyCell.Appearance.BackColor, you are creating an Appearance object for every cell. This is inefficient, becuase you will have lots of duplicate appearance objects you don't really need. It would be better to create 3 Appearance objects (one for each color) and then assign the entire Appearance to the cell.
Do I have to create the three appearances (red, yellow, green) in the InitializeLayout event for each of the grids and combos I want to use it on, or is there a way to make global appearances that I can reference?
Thanks,~Kelly
Hi Kelly,
I would probably recommend creating the appearance as part of the grid.DisplayLayout.Appearances collection. Which means you create the appearances for each grid.
You can try creating the appearance outside the grid and sharing it amongst all of the grids, but I think there might be a problem with that because of the ImageList. The Appearance needs the grid to get to the grid's ImageList in order to get images from an ImageList. Even if these are not being used, it might cause an error if you try to use the same Appearance object in more than one grid. You can try it out, though. If there is a problem, you will get an exception when the grid's try to paint. If there's no exception and both grids display okay, then I would say it's probably safe to use the same appearance for all grids.
Hi Mike,Creating global appearances did work. I tried to implement your suggestions, so does this now look more efficient?
Dim LightYellowApp, LightGreenApp, LightRedApp, LightGreyApp As New AppearanceLightYellowApp.BackColor = Me.LightYellowLightGreenApp.BackColor = Me.LightGreenLightRedApp.BackColor = Me.LightRedLightGreyApp.BackColor = Me.LightGreyRowName.Cells(MyCol.Key).Appearance = Me.LightRedAppPrivate Sub UltraGrid_InitializeLayout(sender, e) For Each MyCol As UltraGridColumn In .UltraGrid.DisplayLayout.Bands(0).Columns If IsNumeric(MyCol.Key) = True Then .UltraGrid.DisplayLayout.Bands(0).Columns(MyCol.Key).CellAppearance = Me.LightYellowApp End If NextEnd SubPrivate Sub UltraGrid_InitializeRow(sender, e) AddConditionalFormatting(e.Row, False)End SubPrivate Sub AddConditionalFormatting(ByRef RowName As UltraGridRow, ByVal IsAssignmentsGrid As Boolean) Dim CellValue As Decimal For Each MyCol As UltraGridColumn In RowName.Band.Columns If IsNumeric(MyCol.Key) Or MyCol.Key = "Total FTE" Then If IsAssignmentsGrid = True AndAlso MyCol.Key <> "Total FTE" AndAlso RowName.Cells(MyCol.Index + 2).Value = "Y" Then RowName.Cells(MyCol.Key).Appearance = Me.LightGreyApp Else ' not assignments grid, or is and it is the total fte column If (Not RowName.GetCellValue(MyCol) Is DBNull.Value) AndAlso RowName.GetCellValue(MyCol) <= 0 Then CellValue = RowName.GetCellValue(MyCol) If CellValue < 0 Then RowName.Cells(MyCol.Key).Appearance = Me.LightRedApp End If Else ' value > 0 or is null RowName.Cells(MyCol.Key).Appearance = Me.LightGreenApp End If End If End If NextEnd Sub
Thank you again for your time and assistance,Kelly
Yes, this looks a lot more efficient to me. The only minor inefficiency I see here is that you are calling GetCellValue with for the same column several times. It would probably be metter to call it once and store the value. But that's a very small thing and probably won't make any noticable difference.
Hi Gregory,
Sorry, I got a little mixed up there. I thought we added a SelectedAppearance to the row, but it's actually only available on the cell.
Anyway, I think you can achieve essentially the same thing using the row.CellAppearance, instead of row.Appearance. CellAppearance will override the selected appearance, I think.
If I am wrong, then the alternative would be to loop through cells in the row and apply the appearance to the cell.Appearance and possibly also the cell.SelectedAppearance and maybe also the cell.ActiveAppearance if you want.
Yes. In addition to setting the Appearance on the row, you can set the SelectedAppearance, also. This was added a couple of years back, so if you are using a very old version of the controls, it might not be available. In that case, it's much more difficult to handle and you would have to use a DrawFilter.
Hey Mike,
I have my grid row backcolor turning red thanks to your posts, but if my red row happens to be the first row in the grid when that row is the selected row the selected row color of orange seems to take precidence over the red color. As soon as I click off of that row then I can see the red backcolor. Is there a way to force the red backcolor to override the selected row color?
Gregory
Normal 0 false false false EN-US ZH-CN X-NONE
e.Row.Update(); has done the trick
Many Thanks Boris.
Ganesh.