Guys,
Congratulations on the new forums look!
I have a major major issue - i'm using WinGrid and inserting an image as a progress bar image background which is then assign as an EditorControl on one of the cells in each row.
The issue is the these images when loaded to all the rows at once are causing major memory issues.
I am using load on demand, and Initialize row method since the image is depended on the valued of other rows.
But - when the grid is sorted - it seems to bring all the images and memory consumption of the grid rises to up to 200M - i have some tabs like this - and this causes memory consumption of almost 1.5G! ;-(
I have tried using teh VisibleRows - and whenever the scroll region changes - draw the images only for the visible rows - assuming that for a grid containing 1000s of rows only a few will become visible in practice.
This works but not for the sorting - when the grid is being sorted - the VisibleRows are not affected some how though in practice they do...
How can i get the VisibleRows after a sort operation?
Is there a way to make the grid not initialize ALL the rows after a sort operations (i'm using UltraDataSource).
This would actually save all the trouble from me.
My second problem - which is a BIG BIG problem is that my images are not being disposed when the grid does - or when the progress bar is being disposed (i've tried both).
I have tried putting the image as a cell background - in this case the image is being disposed - but looks differently and in addition - when a row is active it is being colored and hides my image.
Can you guys pls help? It seems like a dead end - whatever i try - some of the issues are being solved and other rises - you help is really impotent.
I'm using the image since you guys don't have a multi-color progress bar - my progress bar have sevral segments, each segment has a diffrent color and precentage size. My row data represent a task, each task is consisted of jobs - and the progress bar image shows a colored segment for each status of jobs - like running, waiting, completed and so on... if i got the wrong idea that you guys don't have a progress bar like this - please correct me - this is the root problem - if this is solved - all the other is irrelevant.
This progress bar is a real issue for us - i wanted to know also if we can pay for support that will solve this problem if this is not a trivial one - can i talk to someone and see if this multi-color progress bar can be addressed by you?
Thanx!
-Gili
Mike - Thanx!
It solved ALL my problems!!!
For those who might ever want an example for the bellow - drawing an image onto a cell UI element + drawing text:
-----------------------------------------------------------------------------------------------------------------------------------------
namespace OctopusMonitorII.DrawFilters{ public class UltraGridCellDrawFilter : IUIElementDrawFilter { #region Implementation of IUIElementDrawFilter public Infragistics.Win.DrawPhase GetPhasesToFilter(ref Infragistics.Win.UIElementDrawParams drawParams) { var cell = (UltraGridCell)drawParams.Element.GetContext(typeof(UltraGridCell)); if (cell != null && cell.Column.ToString() == "Progress") if (drawParams.Element is CellUIElement) return DrawPhase.BeforeDrawElement; return DrawPhase.None; } public bool DrawElement(Infragistics.Win.DrawPhase drawPhase, ref Infragistics.Win.UIElementDrawParams drawParams) { CellUIElement cellUIElement; UltraGrid objGrid; UltraGridRow objRow; Image objImage; switch (drawPhase) { case Infragistics.Win.DrawPhase.BeforeDrawElement: //Get the ImageUIElement cellUIElement = (CellUIElement)drawParams.Element; //Get a reference to the grid control. This is only necessary in //order to get the ImageList. If you are using images from somewhere //else, you do not need this line. objGrid = (UltraGrid)cellUIElement.Control; //Get the row we are dealing with. objRow = (UltraGridRow)cellUIElement.GetContext(typeof(UltraGridRow)); //Get the image related with this row. var completed = Convert.ToInt32(objRow.Cells["Completed"].Value); var waiting = Convert.ToInt32(objRow.Cells["Waiting"].Value); var failed = Convert.ToInt32(objRow.Cells["Failed"].Value); var running = Convert.ToInt32(objRow.Cells["Running"].Value); var total = completed + waiting + failed + running; var progressBar = new SegmentedProgressBar.SegmentedProgressBar(); var segments = new SegmentsSettingsCollection(0, 100); segments.Add(new SegmentSettings((int)(100 * completed / total), Color.ForestGreen)); segments.Add(new SegmentSettings((int)(100 * failed / total), Color.Red)); segments.Add(new SegmentSettings((int)(100 * running / total), Color.Orange)); progressBar.SetSegments(segments); objImage = progressBar.GetImage(); //drawParams.AppearanceData.Image = objImage; //progressBar.DrawToGraphics(drawParams.Graphics); drawParams.DrawImage(objImage, drawParams.Element.Rect, true, null); drawParams.DrawString(drawParams.Element.Rect, completed + "%", false, false); return true; } return false; } #endregion }}
gbenshim said:In the DrawElement i have inserted a code that assigns my image to the cells background - should this work?
No, that's not a good idea. You should never set peristant properties like Appearances from within a DrawFilter. What you can do is either:
The first method is probably a lot easier.
gbenshim said:I have also tried drawing the image directly to the cell by calling objRow.GetUIElement().Control.CreateGraphics()
This isn't a good thing to do either. The drawParams.Graphics already gives you the graphics object. So if you are going to draw onto it, you can just use the event args, you don't have to dig for it. :)
It seems to be what i need - but i was unable to completely understand how to implement this.
I have searched for some articles about the DrawFilter but there are still issues that are unclear to me.
I have implemented the IUIElementDrawFilter and assigned it to the grid.
In the DrawElement i have inserted a code that assigns my image to the cells background - should this work?
Check this code:
public bool DrawElement(Infragistics.Win.DrawPhase drawPhase, ref Infragistics.Win.UIElementDrawParams drawParams) { RowCellAreaUIElement objImageUIElement; UltraGrid objGrid; UltraGridRow objRow; Image objImage; switch (drawPhase) { case Infragistics.Win.DrawPhase.AfterDrawElement: //Get the ImageUIElement objImageUIElement = (RowCellAreaUIElement)drawParams.Element; //Get a reference to the grid control. This is only necessary in //order to get the ImageList. If you are using images from somewhere //else, you do not need this line. objGrid = (UltraGrid)objImageUIElement.Control; //Get the row we are dealing with. objRow = (UltraGridRow)objImageUIElement.GetContext(typeof(UltraGridRow)); //Get the image related with this row. var completed = Convert.ToInt32(objRow.Cells["Completed"].Value); var waiting = Convert.ToInt32(objRow.Cells["Waiting"].Value); var failed = Convert.ToInt32(objRow.Cells["Failed"].Value); var running = Convert.ToInt32(objRow.Cells["Running"].Value); var total = completed + waiting + failed + running; var progressBar = new SegmentedProgressBar.SegmentedProgressBar(); var segments = new SegmentsSettingsCollection(0, 100); segments.Add(new SegmentSettings((int)(100 * completed / total), Color.ForestGreen)); segments.Add(new SegmentSettings((int)(100 * failed / total), Color.Red)); segments.Add(new SegmentSettings((int)(100 * running / total), Color.Blue)); progressBar.SetSegments(segments); objImage = progressBar.GetImage(); objRow.Cells["Progress"].Appearance.ImageBackground = objImage; objRow.Cells["Progress"].Appearance.ImageBackgroundStyle = ImageBackgroundStyle.Stretched; return false; } return false; }
Most of the lines deal with creating the image, the last 2 lines simply assign the image.
This works and works good but... this grid is part of a UserControl which has UltraProgressBar located above the grid - from some weird reason - all GUI elements located above the grid are not rendered well and in practice they are not being painted. If the GUI control located beneath the grid - then it is ok. I know this might seem VERY weird- but this is what happans - i have tried removing and readding it and other stuff - but this didn't help - i don't undestand why this happans since this is a totaly diffrent control (?...?)
I have also tried drawing the image directly to the cell by calling objRow.GetUIElement().Control.CreateGraphics() and drawing onto this graphic object (and invalidating in the end the UI element) using the objRow.GetUIElement().Draw(...) method - i wasn't sure though what rectangle to give it and when i gave it an arbitary recatngle (10,100) this was a mass - the entire form got confused from it and rendering got wrong. Is this the way it should be done?... Am i making a mass here?
Is there a way to assign my image without drawing it directly to the grid?
There is a phase BeforeDrawImageBackground in drawParams.Element but there is not image object in the cell UI element... Why is that? I wasn't able to assign my image to the UI element, and this is why i tried assgining directly to the control - maybe this causes drama for the rendering.
You help will be apreicated...
Thanx a lot,
Gili
Hi Gili,
Are you assigning an Editor to each cell, or to the column as a whole? It seems to me that you only need one editor for the whole column.
Anyway, when you sort the grid, the grid has to Initialize all of the rows. There's no way around this. It has to load all of the rows in order to get the data in order to sort them.
Disposing the images is something the grid cannot do, because the grid has no way of knowing if the images you assigned are being used by something else. If you create the image, then it's up to you to dispose it.
To make this more efficient, it sounds to me like you need to create some sort of caching mechanism and apply the images to the grid using a DrawFilter.
Basically, you would create a Dictionary. I assume your progress bar image can be created using only a few values. So you could create a class or a struct that contains all the information you need to draw the ProgressBar image let's call this ProgressBarImageInfo for the sake of discussion. You then override the GetHashCode and Equals methods of this class to they are unique and comparable and you can use them as Keys into the dictionatry. So the dictionary keys are ProgressBarInfo objects that contain progress bar information and the values are the images of the progressbar.
I would probably create a class that stores the Dictionary and has method for getting an image, given the ProgressBarInfo. This method could check to see if the item already exists in the dictionary and if so, return the existing image. Otherwise, it creates the image and adds it into the dictionary.
This provides a couple of advantages:
Then you take your code out of InitializeRow. You do not assign an ImageBackground to the cell. Instead, you use a DrawFilter an draw the image onto the CellUIElement yourself. This way, only visible cells will need their images.
If you are not familiar with DrawFilters, you can check out the Infragistics Knowledge Base. There are lots of articles and samples there. Also, I recommend that you get the Infragistics UIElementViewer Utility. It helps a lot when dealing with UIElements.