I have a bound grid with several columns. One column is a custom drop-down list. Items of list depend on row data (varies from row to row). Setup of such column is performed in InitializeRow event by creating ValueList, adding required items (with correct one which corresponds to bound data), and setting this ValueList to required column's cell with cell.ValueList = list. When grid is shown for the first time and data (around 1200 rows) is bound, SetDataBinding executes in no time (<0,1s) (it is possible that data is bound while grid is not visible yet).But, if other data of the same amount is bound to the same grid, SetDataBinding blocks for about 20s.
I've analyzed execution with performance profiler and found that while setting value list to cell - cell.ValueList = list - redraw/invalidation of the grid is invoked which slows down performance: Infragistics.Win.ControlUIElementBase.VerifyIfElementsChanged(Boolean, Boolean), Infragistics.Win.UIElement.VerifyChildElements(Boolean)Infragistics.Win.UltraWinGrid.UltraGridUIElement.VerifyChildElements(ControlUIElementBase, Boolean)... etcIf I comment out cell.ValueList = list; line, grid is bound in milliseconds every time.Code of setting cell.ValueList is executed in BeginUpdate/EndUpdate of grid.I've tried several other options (SuspendRowSynchronization, BeginInit, even grid.Visible = false) but with no luck. I suspect that after data is bound to a grid for the first time or grid is drawn for the first time, any subsequent bindings/redraws are not suspended in the same way?
Is there any way to suspend all grid repainting/invalidating and invoke them after all cell.ValueList's are set? Or somehow suspend cell.ValueList invalidations?
Hi,
Do I understand correctly that you are using BeginUpdate and EndUpdate inside the InitializeRow event surrounding the code that set the ValueList property on the cell?
If that's the case, have you tried removing the BeginUpdate/EndUpdate from that event?
It seems to me that calling these methods inside InitializeRow is a bad idea and will probably slow your application down rather than speed it up.
Invalidating the grid (or any portion of it) is a very fast operation. So causing an invalidate inside InitializeRow should not cause a problem.
But once you call EndUpdate, you are forcing the grid to paint, which is much more expensive and that could certainly slow things down.
BeginUpdate and EndUpdate are intended for use when you are performing a lot of operations all at once. So using them inside InitializeRow doesn't make a lot of sense and could actually cause problems.
Also.... Assigning a ValueList to each cell in the column is probably not a good idea, anyway. You might want to check out this article which explains a better way to achieve different lists on each row.
Creating a dropdown list in a grid cell whose list values are dependent on another cell - Windows Forms - Infragistics Community
Hello,
Thank you for quick response.
No, I'm not using BeingUpdate/EndUpdate in InitializeRow event.BeginUpdate/EndUpdate surround SetDataBinding method call only (which subsequently invokes multiple InitializeRow).
But your suggestion to use single filtered drop-down seems implementable in our case and more optimal. I will give it a try.
Okay... just so you know, BeginUpdate/EndUpdate won't do much good around SetDataBinding, either, because binding is not a one-time operation, it's a continuous process and it happens asynchronously. So the EndUpdate will be hit almost immediately and the InitializeRow will fire after that.
Using a single filtered dropdown is a much better approach for a number of reasons, including efficiency, but also because you could run into problems with converting from DataValue to DisplayText if you change the ValueList on a cell to one where the current DataValue does not exist. :)
Hey Mike,
Thank you, I was able to implement required functionality with single UltraDropDown, no more performance issues.
But, there are several questions about styling.
In the end of post I'll paste some code, which made UltraDropDown behave more like standard ValueList, end result looks like this:
First row is active selected value (we have background image stretched), 4th row - HotTrack'ed (HotTrackRowCellAppearance.BackColor set).
Standard ValueList looks like this:
How do I achieve the following:
a) We use AppStylist and GridRow role has Selected/Active states with background images. How to reset/override these images, so UltraDropDown would show not image, but ValueList style (orange color with border) for Selected/Active row. Resetting/clearing e.Layout.Override.ActiveRowAppearance, SelectedRowAppearance background on UltraDropDown did not help - or I've reset incorrect properties.
b) How to achieve border around hot-tracked UltraDropDown item, as seen in ValueList.
c) How to properly share code in forum - with tabs, syntax highlight, etc :)
Here is the code I've used so far (maybe some will find it usefull):
In UltraDropDown initialize layout:
e.Layout.BorderStyle = UIElementBorderStyle.Rounded1;
e.Layout.Override.BorderStyleCell = UIElementBorderStyle.None;e.Layout.Override.RowAppearance.BorderAlpha = Alpha.Transparent;
e.Layout.ScrollStyle = ScrollStyle.Immediate;e.Layout.Scrollbars = Scrollbars.Vertical;e.Layout.Appearance.BackColor = Color.White;e.Layout.Override.HotTrackRowCellAppearance.BackColor = Color.FromArgb(255, 171, 63);
e.Layout.AutoFitStyle = AutoFitStyle.ExtendLastColumn;
Main creation filter method for UltraDrop down to size/position correctly:
void IUIElementCreationFilter.AfterCreateChildElements(UIElement parent){ if (parent is UltraGridUIElement) { UltraGridUIElement gridUiElement = (UltraGridUIElement)parent;
// Get drop down control: Control dropDownControl = gridUiElement.Control.Parent;
// Get active cell from where drop-down is invoked: UltraGridCell cell = this.gridControl.ActiveCell;
// This method is called more than once, the first time the drop-down section // is not attached to the UIElements, which explains this "if". if (dropDownControl != null && cell != null) { // Calculate maximum width of drop-down by drop-down column width: UltraGridColumn dropDownColumn = null; UltraGridLayout layout = gridUiElement.Grid.DisplayLayout;if (layout.Bands.Count > 0) { // Get drop-down grid column: if (layout.Bands[0].Columns.Exists(this.columnName)) dropDownColumn = layout.Bands[0].Columns[this.columnName]; }
int width = -1; // Get column widht: if (dropDownColumn != null) { width = dropDownColumn.CalculateAutoResizeWidth(PerformAutoSizeType.VisibleRows, false); width += 25; // Scroll bar width ~ should be get from somewhere? }
// Get UI element of active cell: UIElement cellElement = cell.GetUIElement(); if (cellElement != null) { Rectangle cellRect = cellElement.Rect;
// If cell width is more than required for drop-down control, expand drop-down: if (cellRect.Width > width) width = cellRect.Width;
// Set drop-down width: dropDownControl.Width = width;
// Calculate drop-down location: Point location = new Point(cellRect.Right - width, cellRect.Bottom); location = this.gridControl.PointToScreen(location);
// Set drop-down location: dropDownControl.Left = location.X;
}
acrus said:a) We use AppStylist and GridRow role has Selected/Active states with background images. How to reset/override these images, so UltraDropDown would show not image, but ValueList style (orange color with border) for Selected/Active row. Resetting/clearing e.Layout.Override.ActiveRowAppearance, SelectedRowAppearance background on UltraDropDown did not help - or I've reset incorrect properties.
The UltraDropDown and the UltraGrid rows are both the same UIRole. So the only way to do this would be to add a new StyleSet to your isl file and set the StyleSetName on the UltraDropDown to the new StyleSet name in your isl. That way you could style it completely differently than the grid.
acrus said:b) How to achieve border around hot-tracked UltraDropDown item, as seen in ValueList.
I'm not sure there is any way to do this other than using an ImageBackground with a border in the image.
You could try using the Border style on the GridRow role in your new StyleSet in the isl, but borders in the grid are a little weird. Most objects in the grid only draw one or 2 sides, since otherwise you would end up with double-thick borders between objects.
acrus said:c) How to properly share code in forum - with tabs, syntax highlight, etc :)
Use a code tag.I can't show you the text here, since it would get turned into tags and hidden. But basically it looks like this, only instead of the squiggly brackets you use square brackets:
{ code }
// my code here
{ /code }
a), c) - understood.As for b) - if not through Appearance, maybe there is a way with DrawFilters. Like, after drawing background, draw a border. And assign this filter to grid of UltraDropDown.
acrus said:But, it is drawn only on left/top/right sides of hot traced cell :) For bottom part - only for bottom cell.
Yeah, that's pretty much what I was saying earlier. Rows only draw some borders sides, not all four. So you would have to use a DrawFilter for this.
acrus said:SelectionOverlayBorderColor has no effect.
I tried this out and it works fine for me.
Tried, but SelectionOverlayBorderColor has no effect. As for changing StyleSet for selection, it would be ok. I'm now more interested in HotTracking item. This does the trick for backgroud color:e.Layout.Override.HotTrackRowCellAppearance.BackColor = Color.FromArgb(255, 171, 63); And I've achieved border like this:e.Layout.Override.HotTrackRowAppearance.BorderAlpha = Alpha.Opaque;e.Layout.Override.HotTrackRowAppearance.BorderColor = Color.FromArgb(211, 206, 185);e.Layout.Override.RowAppearance.BorderAlpha = Alpha.Transparent;This way border is drawn only around HotTrack'ed items.
Oh, sure, you could do this with a DrawFilter.
It's a bit tricky, though.
You would need to handle the AfterDrawElement phase of the RowColIntersectionUIElement, I think. You can't do it as part of the drawing of the RowUIElement, because other rows will overlap your row and you will lose part of the borders.
There are also some tricky invalidation issues. When you move the mouse over the dropdown area, individual cells will get incalidated, but not the whole grid, so your border might end up drawing in parts and look odd unless you force an invalidation.
I remember writing some sample code for this in the grid (not the DropDown or Combo) recently.I can't seem to find it, though.
Now that I think about it, maybe you can use the SelectionOverlayBorderColor on the grid's DisplayLayout to get what you want. I'm not sure if it will look exactly like the UltraComboEditor, but it's probably a lot easier than writing the DrawFilter. :)