Skip to content

WinGrid Performance Guide

New Discussion
Mike Saltzman
Mike Saltzman asked on Oct 23, 2009 4:24 PM

The purpose of this article is to provide some general programming practice guidelines and troubleshooting tips to improve performance when using the UltraWinGrid control. Not all of the tips provided here will apply to every application, but it should help with the most common performance issues a developer is likely to encounter.

Performance

1) Painting

Painting the grid, or any control, on the screen can often be a source of performance issues. This is especially the case when multiple operations are performed on the control in code at run-time, each of which causes the control to be invalidated in whole or in part.
For example, suppose you have code to loop through every row of the grid and update the value in a cell:
 
        private void ultraButton1_Click(object sender, EventArgs e)
        {
            foreach (UltraGridRow row in this.ultraGrid1.Rows)
            {
                row.Cells[“Price”].Value = (double)row.Cells[“Price”].Value + 1.0;
            }
        }
Each time a cell is updated, some part of the grid will be invalidated and the grid may re-paint itself on the screen many times. In a case like this, you can prevent the grid from painting more than once by disabling the painting before the loop begins and re-enabling it once all operations are complete.  You do this with the BeginUpdate and EndUpdate methods.
 
        private void ultraButton1_Click(object sender, EventArgs e)
        {
            this.ultraGrid1.BeginUpdate();
 
            try
            {
                foreach (UltraGridRow row in this.ultraGrid1.Rows)
                {
                    row.Cells[“Price”].Value = (double)row.Cells[“Price”].Value + 1.0;
                }
            }
            finally
            {
                this.ultraGrid1.EndUpdate();
            }
        }
Notice that a try…finally block is used here.  This is to make sure that no matter what happens, the grid’s painting always gets turned back on eventually.
Another case, similar to this, is when you are making changes to the grid’s DataSource directly. Most data sources will notify the grid of changes and the grid will do some internal process of these changes, even if it is not painting. You can turn off this internally processing and gain some performance using the SuspendRowSynchronization/ResumeRowSynchronization methods. These methods should always be called inside a block with BeginUpdate and EndUpdate. For example:
 
        private void ultraButton1_Click(object sender, EventArgs e)
        {
            this.ultraGrid1.BeginUpdate();
            this.ultraGrid1.SuspendRowSynchronization();
 
            try
            {
                // Get the DataTable the grid is bound to. This assumes the
                // data source is a DataTable.
                DataTable dt = (DataTable)this.ultraGrid1.DataSource;
 
                foreach (DataRow row in dt.Rows)
                {
                    row[“Price”] = (double)row[“Price”] + 1.0;
                }
            }
            finally
            {
                this.ultraGrid1.ResumeRowSynchronization();
                this.ultraGrid1.EndUpdate();
            }
        }

2) The CellDisplayStyle property.

By default, every cell in the grid uses an Editor to display and edit its value. Editors have a lot of power and flexibility, providing valuelists, color choosers, date dropdown, masking, checkboxes, buttons and many other features. But with all these features come extra overhead and more complex painting. The grid cannot know what features your application will and will not need at run-time, so by default, all features are enabled. However, if you know you will not be using certain features in a column, you can turn some features off using the CellDisplayStyle property. For details on the CellDisplayProperty and the various options available, please refer to the Infragistics Online Help.

3) ValueLists

Another common cause of slowdowns in the grid is the improper use of ValueLists (include ValueList, BindableValueList, UltraCombo, UltraComboEditor,  and UltraDropDown). ValueLists can provide a dropdown list in a cell. But it’s important to realize that the grid will need to search the list quite often, especially if the DataValue/DisplayValue feature is used and the grid needs to translate values into user-friendly display text.
Make sure data types match – If the DataValue values in the ValueList are a different DataType that the values in the actual grid cell, this can cause performance problems for several reasons. First, the grid is going to need to convert the value from one data type to another. Second, this conversion process may result in an Exception. These exceptions will be caught and handled by the grid. But the raising of exceptions takes a large toll on performance, even when those exceptions are caught. So it’s important to make sure that the DataValues in your ValueList are exactly the same data type as the values in the grid.
Make sure every grid cell value exists on the list – Another common ValueList pitfall is when the value in the grid cell does not exist on the list. Suppose, for example, you have a column in the grid with integer values ranging from 1 to 100. Now let’s say there is a ValueList attached to the column with values from 1 to 100. This is fine and, on average, the grid will need to do 50 comparisons to find the matching item on the list for each cell that paints. But now suppose that every cell in the column starts off with a value of 0. In this case, the grid must search all 100 items in every cell that paints before it can determine that the item does not exist on the list. Adding a value of 0 to the ValueList would alleviate this problem.
Binary searching – The UltraDropDown control has the capability of doing binary searching. In order to perform a binary search, the DropDown must keep an internal sorted list of the DisplayValues on the list. This means there is a small performance hit the first time the dropdown is used since it has to build the list. But every search after that will be much faster than a linear search would be. So using UltraDropDown may gain your application a significant performance boost at the cost of a small initial hit. Note that the UltraDropDown control has a property called DropDownSearchMethod, which default to Binary, but can be set to Linear, if you don’t want to use binary searching.
EditAreaDisplayStyle – When you attach an UltraDropDown (or UltraCombo) to a cell and select an item, the appearance of the item is copied into the grid cell. So if you have an image applied to a cell in the dropdown, that image will appear in the cell when the corresponding item is selected. In order to handle this, the DropDown needs to search the list to find the largest image and leave space for that image in the grid cell. This searching of the list can slow down the painting of the grid. So in v6.1 of the UltraDropDown, a new property was added called EditAreaDisplayStyle. By setting this property to DisplayText, you can tell the dropdown that the grid cell does not need to show images based on the selected item. This is an especially good idea if your dropdown is not actually using images.

4) Recursion

The UltraWinGrid drills down into its data source and creates a CurrencyManager for every level. If you bind the grid to a recursive data source, this means that the grid will, by default, create 100 levels of CurrencyManagers. The number 100 is the default of the MaxBandDepth property.
Each level of depth in the data source will increase the number of CurrencyManagers in a logarithmic scale. So the first level of the grid only requires 1 CurrencyManager. The second level requires one CurrencyManager for each row in the first level. The third level of depth requires one CurrencyManager for each row in the second level, and so on. This can quickly add up to a huge usage of memory and make it very difficult for the grid to synchronize its current row with the current Position of the CurrencyManager.
To alleviate this kind of issue, there are serval things you can do.
The first is to set MaxBandDepth to a more reasonable number. Very few users will find it useful to drill down into the data 100 levels deep. They will become lost long before they every reach that point. A value of between 5 and 8 usually gives a good balance between displaying a reasonable depth of data and still having grid that performs well.
The second thing you can do is to set SyncWithCurrencyManager to false. This tells the grid not to synchronize the current row with the current position of the CurrencyManager. This means that if there are other controls in the application bound to the same data source as the grid, changing the grid’s current row will not position the CurrencyManager and thus not update the other controls. But very often, this is not necessary, anyway.
Also, using a BindingSource may also help. See the next section.

5) Use a BindingSource

In Visual Studio 2005 (or more accurately in the DotNet Framework CLR 2.0), some changes were made to the DotNet BindingManager that might cause performance problems with the grid when it is bound directly to a DataTable or DataSet under certain conditions.
Wrapping the grid’s Data Source in a BindingSource corrects these issues. See Infragistics KB article #9280 for more details.

6) Exceptions

As mentioned briefly above (under ValueLists) thrown exceptions can have a big impact on performance, even if those exceptions are caught and handled. So it’s often a good idea to set the Visual Studio IDE to break on all run-time exceptions and reveal any exception that might be occurring. If exceptions are occurring, then where they occur can often provide information on how to avoid them.

Memory Usage

If you are concerned about reducing the amount of memory used by the grid, then there are several important things you can do to reduce it.

1) Don’t reference cells unneccessarily – use GetCellValue, instead.

The grid does not create UltraGridCell objects for every row of data. Cells are only created as neccessary. So whenever possible, you should avoid accessed a cell. For example, suppose your code is using the InitializeRow event of the grid in order to calculate a total. For example:

 
        private void ultraGrid1_InitializeRow(object sender, InitializeRowEventArgs e)
        {
            e.Row.Cells[“Total”].Value = (double)e.Row.Cells[“Quantity”].Value * (double)e.Row.Cells[“Price”].Value;

        }

This code references three cells in each row of the grid, thus creating a lot of objects which are potentially unneccessary. This can be avoided using methods on the row to deal with cell values, rather than the cell objects themselves. Like so:


        private void ultraGrid1_InitializeRow(object sender, InitializeRowEventArgs e)
        {
            UltraGridColumn quantityColumn = e.Row.Band.Columns[“Quantity”];
            UltraGridColumn priceColumn = e.Row.Band.Columns[“Price”];
            e.Row.Cells[“Total”].Value = (double)e.Row.GetCellValue(quantityColumn) * (double)e.Row.GetCellValue(priceColumn);

        }

By using the GetCellValue method, we can eliminate 2 cells per row in this example and save memory.

2) Re-use Appearances

Another common use for the InitializeRow event is to apply an appearance to a cell based on the Value of that cell. Applying an appearance to a cell requires getting a reference to the UltraGridCell, so that is unavoidable. But you can save memory by re-using the same appearance object for multiple cells. Suppose, for example, that you want to change the ForeColor of a cell to red for negative numbers and black for positive numbers. You might do something like this:

        private void ultraGrid1_InitializeRow(object sender, InitializeRowEventArgs e)
        {
            // Get the value of the Total column.
            UltraGridColumn totalColumn = e.Row.Band.Columns[“Total”];
            double total = (double)e.Row.GetCellValue(totalColumn);
 
            if (total < 0)
                e.Row.Cells[“Total”].Appearance.ForeColor = Color.Red;
            else
                e.Row.Cells[“Total”].Appearance.ForeColor = Color.Black;

        }

This code will create a cell for every row. That is unavoidable, since the cell must be created in order to have an Appearance. The bigger problem here is that the Appearance property on the cell is lazily created. That means that we are not only creating a cell for each row, but a new Appearance object for each row. And since there are only two possible colors, we end up creating a large number of identical appearance objects.

A better way to do this is to create the Appearances we need up front and then re-use the same appearance wherever it is needed.

 
        private void ultraGrid1_InitializeLayout(object sender, Infragistics.Win.UltraWinGrid.InitializeLayoutEventArgs e)
        {
            // Create an appearance for negative values
            Infragistics.Win.Appearance negativeAppearace = e.Layout.Appearances.Add(“Negative”);
            negativeAppearace.ForeColor = Color.Red;
 
            // Create an appearance for positive values
            Infragistics.Win.Appearance positiveAppearace = e.Layout.Appearances.Add(“Positive”);
            positiveAppearace.ForeColor = Color.Black;
        }
 
        private void ultraGrid1_InitializeRow(object sender, InitializeRowEventArgs e)
        {
            UltraGrid grid = (UltraGrid)sender;           
 
            // Get the value of the Total column.
            UltraGridColumn totalColumn = e.Row.Band.Columns[“Total”];
            double total = (double)e.Row.GetCellValue(totalColumn);
 
            if (total < 0)
                // Use the Negative Appearance already defined in the grid’s Appearances collection.
                e.Row.Cells[“Total”].Appearance = grid.DisplayLayout.Appearances[“Negative”];
            else
                // Use the Positive Appearance already defined in the grid’s Appearances collection.
                e.Row.Cells[“Total”].Appearance = grid.DisplayLayout.Appearances[“Positive”];

        }

Another benefit to this approach is that you can change the appearance everywhere en masse. For example, suppose your users want to use Green instead of Black for positive appearances. You could, at run-time, set the ForeColor of the “Positive” Appearance object, and every cell in the grid that was using that appearance would update automatically.

Sign In to post a reply

Replies

  • 0
    Amiram Korach
    Amiram Korach answered on Oct 26, 2008 10:32 AM

    I just did a benchmark to the GetCellValue. With 100000 rows of three integers I saved 28MB of memory! (but just 0.2 seconds) now I'm going to replace it.

    Just to be easy, you can add too extension methods so you can get the value by the column name or index:

    namespace Infragistics.Win.UltraWinGrid

    {

       public static class UltraGridRowExtension

       {

       /// <summary>

       /// Returns the data value for a cell from the database

       /// </summary>

       /// <param name="row">The row contains the cell</param>

       /// <param name="columnName">The cell column name</param>

       /// <returns>The data value for a cell from the database</returns>   public static object GetCellValue(this UltraGridRow row, string columnName)

       {

          return row.GetCellValue(row.Band.Columns[columnName]);

       }

       /// <summary>

       /// Returns the data value for a cell from the database

       /// </summary>

       /// <param name="row">The row contains the cell</param>

       /// <param name="columnIndex">The cell column index</param>

       /// <returns>The data value for a cell from the database</returns>   public static object GetCellValue(this UltraGridRow row, int columnIndex)

       {

          return row.GetCellValue(row.Band.Columns[columnIndex]);

       }

       }

    }

    • 0
      Sundaresan
      Sundaresan answered on Mar 13, 2009 2:40 PM

      amiram can you share this memory test project

      • 0
        Amiram Korach
        Amiram Korach answered on Mar 15, 2009 12:14 PM

        Attached

  • 0
    Walter
    Walter answered on Nov 3, 2008 2:09 PM

     Great article Mike!

    i have a first question: Why exist the Value property(i mean the get part of this property) of a cell and GetValueCell method?

     

    thank you

    • 0
      Mike Saltzman
      Mike Saltzman answered on Nov 3, 2008 5:02 PM

      The Value property on the cell is more convenient to use and easier to discover so it makes working with the grid more intuitive. In a case where the cell has already been created, it's easier to use Value then to walk up to the Row and use GetCellValue. Also, you need the Value property for the setter. 🙂

      • 0
        Vern
        Vern answered on Nov 10, 2008 7:07 AM

         Mike, great article. You article is a great headup and comes at a very good time personally since I would designing for the next phase of my project that involves changing Appearance for cells. Here's the problem:

         – Depending on the user's selection, the data pulled over from server may have as many as 100 rows and 100 columns (about 10000 cells)

        – Depending on some application setting, half of these cells may need to be have it Appearance set by the business logic

        – The business logic has four parameters and affects Appearance differently. Two parameters affects the background color, one Appearance affects the bolding of foreground and last one affects the foreground.

        – These four parameters are  independent i.e. so one does not affect the other. If the two parameter that affect background happen together, then one takes precedence over the other.

        ___________________________________________________________________

        Question:

           – Reading your article, seems like I would be cause instantiation of the Cell Object for all those cells that the business logic wants to set the Appearance for. If that is around 5000 cells, how big a perrformance concern is that?

           –  Reading your article, I will be instantiating about 5000 Appearance object for each Cell. How big a concern is that?

           – In your article you suggest caching the copy of a Appearance and reusing that. In my case, the Appearance is a result of some combination of the independent four parameters. I will have to create an elaborate scheme to cache for various parameter combination. You think that would worth doing? 

        – Any other suggestions?

      • 0
        Mike Saltzman
        Mike Saltzman answered on Nov 10, 2008 3:22 PM

        [quote user="vrn"]- Reading your article, seems like I would be cause instantiation of the Cell Object for all those cells that the business logic wants to set the Appearance for. If that is around 5000 cells, how big a perrformance concern is that? [/quote] 

        A lot of this will depends on the machine you are running on. Obviously, a faster machine with more memory will be better able to handle this than a slower one with less memory. So it's hard for me to say whether 5000 cells will be too many. The best thing for you to do would be to protoype it and try it out on a typical user machine and see how it goes. 

        [quote user="vrn"]

        –  Reading your article, I will be instantiating about 5000 Appearance object for each Cell. How big a concern is that?

           – In your article you suggest caching the copy of a Appearance and reusing that. In my case, the Appearance is a result of some combination of the independent four parameters. I will have to create an elaborate scheme to cache for various parameter combination. You think that would worth doing? 

        [/quote]

        From your description here, it sounds like you don't really need 5000 appearance objects. You have a limited number of appearances that you actually need. You can certainly limit the number of appearances you create to only the combinations you need and then re-use the same appearances for different cells. What I would do in a case like this is write a sort've caching class with a Dictionary. The key of the dictionary would be some class that contains the information you need to get the appearance – whatever factors are important. Then you use that object to see if the apearance already exists in the dictionary, and if so, you use it, otherwise, you create it and add it to the dictionary. 

        It's really not all that elaborate a scheme, I've done this myself many times. The trickiest part is creating some object that contains the information you need. You have to override Equals and GetHashTable on this key object so that the dictionary works correctly, but it's really not that hard. 

        [quote user="vrn"]- Any other suggestions? [/quote]

        If it turns out that the caching is too complex or 5000 cells is too much, there is another way you can apply appearances to the cells without forcing the creation of more than a few cells and without creating any appearance objects at all. You could use a DrawFilter, instead. The DrawFilter will only apply to cells that are actually visible on the screen. It's essentially like overring the OnPaint, so you are affecting the painting of the grid without using Appearances. Cells that are displayed on the screen are already created, anyway, so there's no concern about creating unneccessary cells inside the Drawfilter.

        This will drastically reduce the amount of memory your application needs. But the down side is that a DrawFilter is more complicated to create.

      • 0
        Pradeep
        Pradeep answered on Nov 12, 2008 2:58 PM

        Hi, I am
        using the GetCellValue in the following way. I am able to get the value of a
        cell(where mouse points).

         

        But i am
        having requirement like, i know the row number and column number, I want to get
        the value in that cell.

        I have
        tried in so many ways. But I am unable to find the answer. So Please help me.
        Thanks in advance.

        Please find the sample code below. 

         

        private
        void ultraGrid1_MouseMove(object sender, MouseEventArgs e)

                {

                    int lCol = 0;

                    int lRow = 0;

                    int absPos = 0;

         

                    Infragistics.Win.UIElement
        aUIElement;

                    aUIElement =
        ultraGrid1.DisplayLayout.UIElement.ElementFromPoint(new Point(e.X, e.Y));

                    UltraGridRow tRow;

                    UltraGridColumn tCol;

                    tCol = (UltraGridColumn)aUIElement.GetContext(typeof(UltraGridColumn));

                    tRow =
        (UltraGridRow)aUIElement.GetContext(typeof(UltraGridRow));

                    // 
        if a row was found display the band and row index

                    if (!(tRow == null))

                    {

                        lRow = tRow.Index + 1;

                       
        //MessageBox.Show(tRow.Index.ToString());

                    }

                    else

                    {

                        //MessageBox.Show("No row
        or column associated");

                    }

                    if (!(tCol == null))

                    {

                        lCol = tCol.Index + 1;

                        //MessageBox.Show("Col=" +
        tCol.Index.ToString());

                    }

         

         

                    //Wingrid

                    if (mCurrentSampleObj != null)

                    {

                        absPos =
        (int)mCurrentSampleObj.get_AbsolutePosition();

                        if (lCol > 1 && lRow
        > 0)

                        {

                  string ToolTipText =
        tRow.GetCellValue(tCol).ToString();  
        // Gets the text where
        mouse points(Cell pointed by mouse).

          // But here i want to get the value of particular cell(specified
        column given by us. For example Column =4, Row number will be the same as given above)

                            toolTip1.SetToolTip(ultraGrid1,
        ToolTipText);  

         

        //arow.Index = lRow-1;

                            //toolTip1.SetToolTip( ultraGrid1,
        arow[COL_DESCRIPTIONS – 1].ToString());

                        }

                        else if (lCol == 1 &&
        lRow > 0)

                        {

                           
        toolTip1.SetToolTip(ultraGrid1, severityImage);

                        }

                        else

                        {

                           
        toolTip1.SetToolTip(ultraGrid1, "");

                        }

                    }

                    TEMSDatabaseBOM.SAMPLEPOSITION
        tempint = (TEMSDatabaseBOM.SAMPLEPOSITION)absPos;

                    mCurrentSampleObj.set_AbsolutePosition(ref
        tempint);

        }

      • 0
        Pradeep
        Pradeep answered on Nov 13, 2008 12:11 PM

         Hi,

        I got the Solution for this.

        Regards,

        Pradeep. 

         

      • 0
        Mike Saltzman
        Mike Saltzman answered on Nov 13, 2008 2:05 PM

         Hi Pradeep,

        In a case like this where you are trying to get the value of a cell under the mouse, it would actually be more efficient to use the Value property of the cell than to use GetCellValue.

        The advantage of GetCellValue is that it does not force the creation of an UltraGridCell object. But the cells on the screen are already created. So using GetCellValue doesn't really gain you anything here. In fact, it costs you a little, because you have to call GetContext twice. GetContext is not a terribly expensive operation, but it will save you a little time and code to just use GetContext once to get the UltraGridCell. Then you can get the row from the cell and get any other cell in the row using the Cells collection. 

      • 0
        Pradeep
        Pradeep answered on Nov 14, 2008 7:36 AM

        Hi,

        I am having some doubt regarding GetContext. I am using this method to get the row and column on mouse move. please find the sample code below.

        Infragistics.Win.UIElement aUIElement;
                        aUIElement = ultraGrid1.DisplayLayout.UIElement.ElementFromPoint(new Point(e.X, e.Y));
                        UltraGridRow tRow;
                        UltraGridColumn tCol;
                        tCol = (UltraGridColumn)aUIElement.GetContext(typeof(UltraGridColumn));
                        tRow = (UltraGridRow)aUIElement.GetContext(typeof(UltraGridRow));

                            int lRow = tRow.Index;
                            int lCol = tCol.Index; 

         

        Its working fine. But when i place my mouse on Column header, it is giving row number(lRow) as '0'. 

         

      • 0
        Pradeep
        Pradeep answered on Nov 14, 2008 10:19 AM

         Hi,

        It is giving Column header as Row '0' and 1st row also as row '0'. 

         Please help me out. Its urjent requirement. How to catch whether mouse is clicked on column  header or not( I need to sort the column when i click on column header).

         

        regards,

        Pradeep 

         

         

      • 0
        Pradeep
        Pradeep answered on Nov 14, 2008 10:55 AM

         Sorry, I have not mentioned the code. I am talking about the code mentioned above..

        Regards,

        Pradeep. 

      • 0
        Mike Saltzman
        Mike Saltzman answered on Nov 14, 2008 3:18 PM

        Hi Pradeep,

        Did you read my previous post? I suggest that you use GetContext to just get the cell instead of the row. 

        Anyway, the colmun headers DO have a context of the first row. This is correct. So what you would have to do to get the row it use GetAncestor on the UIElement and get a RowUIElement before you call GetContext. If the RowUIElement is null, then you know you are not on a row. 

      • 0
        Pradeep
        Pradeep answered on Nov 14, 2008 4:42 PM

         Hi Mike,

        Thanks for the reply. I have read your previous post, but little bit confused. Now I got the solution from your reply. Now i am using GetContext for cell. Its working fine for me.

        Regards,

        Pradeep. 

  • 0
    Ceaser
    Ceaser answered on Nov 25, 2008 3:35 AM

    Hi, Mike

    Very much useful information, thanks for posting it.

    May I know where I can find this type of documents?

    Regards,

    Ceaser

    • 0
      James
      James answered on Nov 26, 2008 4:38 PM

      The KB09280 thing doesn't seem to have any Microsoft links.

      When it says it "loads slowly when binding to a DataSet with many relationships" how many are we talking?

      Is this fixed in the .Net Framework 3.5?

      I suppose I'll just have to try it…

      • 0
        Mike Saltzman
        Mike Saltzman answered on Dec 1, 2008 8:10 PM

        This was a weird problem that was introduced into the BindingManager just before the release of the DotNet Framework 2.0. As far as I know, this has not been fixed, and was the result of some updates and improvements made to the BindingManager. My guess is it was to help BindingSources work better.

        Anyway,it's hard to define exactly when it occurs. It's not just a matter of the number of relationships in the data. It can also occur in other cases where there are empty island or bands or with complex data structures.

        If you athink you are experiencing this issue, then the best thing to do is simply to wrap your data source in a BindingSource and that will correct the issue. If it does not help, then something else is wrong.

      • 0
        Vern
        Vern answered on Dec 1, 2008 11:32 PM

        I am having the grid bind to a DataView. Does this issue with binding to DataSet potentially become a performance problem for my app or does the use of DataView shelter me from it?

         

         Thanks!

      • 0
        Mike Saltzman
        Mike Saltzman answered on Dec 2, 2008 2:59 PM

        I don't think a DataView helps. When you bind the grid to a DataSet, you are really binding to a DataView, anyway. So you should use a BindingSource to wrap the DataView.

        Of course, if you are not currently experiencing any problems, then you probably don't need to worry about it. The kinds of problems that would occur are severe performance issues and lockups and they are usually prettty obvious and hard to miss. 

  • 0
    Syed Sadaqat Hussain
    Syed Sadaqat Hussain answered on Dec 5, 2008 6:36 AM

     Hi Mike,

    This article is really helpfull for the develper whose are working on desktop application using Ultrawingrid.

  • 0
    Asad Naeem
    Asad Naeem answered on Dec 7, 2008 8:07 AM

     Hi Mike

    Simply the best article in ultrawingrid world. Please include this article infragistics help as well. So that future users of infragistics may read it locally.

    Regards

    Asad Naeem

  • 0
    Faiz Ahmad
    Faiz Ahmad answered on Jan 7, 2009 6:21 AM

    Hi Mike

        It is very usefull article. Thanks for posting.

     

    Faiz Ahmad

  • 0
    Jamal
    Jamal answered on Feb 10, 2009 9:46 PM

    Mike,

    Regarding number 2, if my column style is set to something like Button or DropDownList, should I leave the CellDisplayStyle to the default Editor? Also, if a column is hidden in Initialize_Layout, should I still set its CellDisplayStyle for a performance benefit?

    Nice article, thanks.

    –J

    • 0
      Mike Saltzman
      Mike Saltzman answered on Feb 13, 2009 2:40 PM

      Hi J,

      [quote user="jammerms"]if my column style is set to something like Button or DropDownList, should I leave the CellDisplayStyle to the default Editor?[/quote]

      It's hard to say with any certaintly. It depends what other features you are using, and I'm not completely sure how CellDisplayStyle will affect a button cell, if at all. But it should be easy enough to test it out and see what happens. Any problems that might occur should be immediately obvious. 

      [quote user="jammerms"]Also, if a column is hidden in Initialize_Layout, should I still set its CellDisplayStyle for a performance benefit?
      [/quote]

      I can't see how it could hurt to do this, but I it's not neccessary. The idea behind CellDisplayStyle is that it saves on the creation of certain UIElements. No UIElements are created for hidden cells, anyway. So CellDisplayStyle will have no effect.

  • 0
    Viswanth
    Viswanth answered on Feb 16, 2009 5:22 AM

    Good article Mike. We have been doing a lot of analysis of the same kind to determine the overhead w.r.t performance.

    Although it is similar to what we found, it gave us good insights to avoid crucial performance issues.

    Thanks.,

  • 0
    Jamal
    Jamal answered on Mar 19, 2009 6:24 PM

    Mike,

    In regards to your first point, do BeginUpdate/EndUpdate and/or SuspendRowSynchronization/ResumeRowSynchronization need to be used when just binding the data source to the grid?

    Example:

    try

    {

      DataTable dtTable = myDAO.GetTable();

      ugGrid.BeginUpdate();

      ugGrid.SuspendRowSynchronization();

      ugGrid.DataSource = dtTable;

    }

    catch ….

    finally

    {

      ugGrid.ResumeRowSynchronization();

      ugGrid.EndUpdate();

    }

     

    Just wondering if there's any performance benefit to that approach, or if the control already suspends itself until InitializeLayout and all InitializeRow events have completed.

    Thanks,

    Jamal

    • 0
      Mike Saltzman
      Mike Saltzman answered on Mar 20, 2009 3:26 PM

      [quote user="jammerms"]

      Mike,

      In regards to your first point, do BeginUpdate/EndUpdate and/or SuspendRowSynchronization/ResumeRowSynchronization need to be used when just binding the data source to the grid?

      Example:

      try

      {

        DataTable dtTable = myDAO.GetTable();

        ugGrid.BeginUpdate();

        ugGrid.SuspendRowSynchronization();

        ugGrid.DataSource = dtTable;

      }

      catch ….

      finally

      {

        ugGrid.ResumeRowSynchronization();

        ugGrid.EndUpdate();

      }

       

      Just wondering if there's any performance benefit to that approach, or if the control already suspends itself until InitializeLayout and all InitializeRow events have completed.

      Thanks,

      Jamal

      [/quote]

       

      Hi Jamal,

      That's an interesting question. My first instinct is to say, there's probably no benefit to this. But I decided to test it out very quickly just to see.

      I bound a grid to a DataTable with 100,000 rows and used the StopWatch class to time it.I ran the test twice each way, which is not really enough for a full statistical analysis, but it should do for a quick test.

      Without the BeginUpdate / SuspendRowSynchronization, the results were:

      1652 milliseconds
      1745 milliseconds

      With the methods, the results where:

      1674
      1700

      So it doesn't look like it make a whole lot of difference.

  • 0
    Vern
    Vern answered on Mar 20, 2009 6:27 AM

    Mike, I remember reading somewhere in this forum about turning off some features of Grid if one does not need it and thereby gaining performance. I thought you had mentioned it in this thread but I do not see to find it here.

    Thanks!

    • 0
      Mike Saltzman
      Mike Saltzman answered on Mar 20, 2009 3:28 PM

      [quote user="vrn"]

      Mike, I remember reading somewhere in this forum about turning off some features of Grid if one does not need it and thereby gaining performance. I thought you had mentioned it in this thread but I do not see to find it here.

      Thanks!

      [/quote]

      It sounds like you are talking about item 2 on the list – the CellDisplayStyle property. This allows you to turn off some features of a column.

       

  • 0
    John
    John answered on Jun 4, 2009 2:44 PM

    [quote user="[Infragistics] Mike Saltzman"]set MaxBandDepth to a more reasonable number. Very few users will find it useful to drill down into the data 100 levels deep[/quote]

    I agree this is an unreasonable number.  In fact, I have had more lockups in Visual Studio from this setting than anything else.  Its okay if you catch it, but if you modify your business entities after the fact you may find yourself unable to open your form in the designer.

    Since this is such an unreasonable number, is there any way the default can be changed to 5 in a future release?

    • 0
      Mike Saltzman
      Mike Saltzman answered on Jun 5, 2009 2:30 PM

      Hi,

      We could probably change the default to a more reasonable number, but I doubt it would help much. The problem is that it's really hard to come up with a number that is reasonable in all cases. You suggested 5 here, but I'm sure there are applications that use more than 5 levels of band depth and work perfectly fine. So changing the default to 5 would cause those applications to suddenly stop showing any data beyond the 5th level.

      The level of depth that you can use depends on a wide range of factors like what kind of data source you are using and the processing power of your machine. On some machines with some data sources, a setting of 10 or even 20 might work fine, whereas on other machines, 8 would be too high.

      We would probably be justified in setting the default to something like 20 or 30. But this could still cause problems and break existing applications for some users. And chances are, it won't help much. Since the performance issues increase geometrically, once you cross the threshhold by even 1 or 2 levels, you're pretty much doomed.

      • 0
        Neil
        Neil answered on Jun 5, 2009 3:15 PM

        It would be nice if this was a configuration option. Something that I could set as a global default and something that I could set at a project level.

      • 0
        Mike Saltzman
        Mike Saltzman answered on Jun 5, 2009 4:02 PM

        Hi Neil,

        Well, there's no way we could create a machine or global default for run-time. But you could set this up yourself so that all new grids created at design-time have a setting of your choice using Presets.

        If you click the Start button on any grid on a form and go to the Presets Manager, there's a checkbox under the presets list that says "Apply this Preset to grids created at design-time."

        So what you can do is create a Preset with all of the settings that you want new grids to have and check that checkbox in the designer. Every time you place a new grid on a form, it will load the settings from that preset automatically. MaxBandDepth is one of the available properties on a Preset.

      • 0
        Neil
        Neil answered on Jun 7, 2009 10:18 PM

        Well, it is true that you learn something new every day. I did not know about presets. My comment above was really a design time thing to avoid the situation where opening a form that has recursive references causes VS to crash or other bad things to happen. Sounds like the presets would do exactly that.

        Thanks

        Neil

      • 0
        John
        John answered on Jun 8, 2009 8:07 PM

        That was exactly what I was looking for.  It would be nice if the presets weren't in the program files directory so that I didn't have to launch as administrator in Vista to edit them (it crashes the designer if VS isn't launched as admin), but once set it does exactly what I needed.

        Thanks!

      • 0
        Mike Saltzman
        Mike Saltzman answered on Jun 9, 2009 2:47 PM

        [quote user="jbailey@baileysw.com"]It would be nice if the presets weren't in the program files directory[/quote]

        What version of the grid are you using? I could be wrong, but I think the most recent versions of NetAdvantage install the presets somewhere else.

        Also, I'm pretty sure if you go to the Options dialog in the Presets section of the grid designer, there's an option there to add your own custom folders to the list of where the grid designer searches for presets.

      • 0
        John
        John answered on Jun 9, 2009 3:09 PM

        I'm using Infragistics 2009 volume 1 which I believe is the latest, although the original install on this workstation was 2008 v1 so the preset location could be based on that version.

        You can put your presets into any folder you wish, but when you create the preset you have to be running as administrator or the designer crashes.  I'm using Vista SP1 and Visual Studio 2008 sp1.

  • 0
    Richard
    Richard answered on Jun 11, 2009 1:09 PM

    We are using windgrids a lot our applications, and in most cases we have a grid which has the first column as a driver for the values in the second which are dynamically added to a value list and then the value list is added to the e.Cell.ValueList. In section 3) value list – Make sure every grid cell value exists on the list, We have a problem as the grid would search every row for the column being changed to find out that the none of the values exist in the currently returned options in the valuelist. We Have noticed that with 40 rows their is a marked delay from when the new value list is returned and when we set the e.Cell.ValueList property to when it display's to the user. Is there a way to stop the windgrid from searching all the cells in the column? And if not then why does it do this search each time?

    • 0
      John
      John answered on Jun 11, 2009 2:10 PM

      I have a similar issue in that the grid appears to loop through all the columns and bands at design time.  I have a grid that represents the tasks in a project plan.  The max band depth is set to 5 to prevent the grid from looping through 100X itterations through the recursive table.

      The grid is painfully slow to work with at design time, but I am okay with that since it has added code to create all the fields and band objects.  But since this code is already there, and the behavior for both new bands and new columns is set to hide, why does it loop through again at run time?  This causes an unacceptable delay when loading the grid even with an empty task collection.

      I'm hoping for my sake that there is a way to turn off this behavior or I'm going to have to redo this using something else.

      • 0
        Mike Saltzman
        Mike Saltzman answered on Jun 11, 2009 4:12 PM

        [quote user="jbailey@baileysw.com"]I have a similar issue[/quote]

        Not sure what you mean by this. This issue does not appear to be similar to any issue described in this thread.

        [quote user="jbailey@baileysw.com"]the grid appears to loop through all the columns and bands at design time.[/quote]

        The grid needs to create the data structure and as such, it will loop through the bands. But it does not crete any rows from the data at design-time and I am not aware of any reason why the grid would ever need to loop through the rows at design-time.

        [quote user="jbailey@baileysw.com"]The grid is painfully slow to work with at design time, but I am okay with that since it has added code to create all the fields and band objects.  But since this code is already there, and the behavior for both new bands and new columns is set to hide, why does it loop through again at run time?  This causes an unacceptable delay when loading the grid even with an empty task collection.[/quote]

        When you assign the DataSource to the grid, it doesn't neccessarily know that it's the same one you assigned at Design-time. In fact, it's not the same instance, so it has to get the structure again. But I have never seen this cause any significant performance issue when MaxBandDepth is set to a reasonable number, and 5 is certainly reasonable.

        So the question is, what is causing the delay. It's hard to guess without knowing more about your application. But I can tell you that the grid will not load child rows by default, so only the root-level rows of the grid should be created initially. If you are getting events of the grid like InitializeRow firing for child rows when you run your application, it must be because something in your code is forcing those rows to be loaded.

        Are you calling ExpandAll on the grid? Are you setting the ExpansionIndicators property to CheckOnDisplay?

      • 0
        John
        John answered on Jun 11, 2009 5:09 PM

        [quote user="[Infragistics] Mike Saltzman"]When you assign the DataSource to the grid, it doesn't neccessarily know that it's the same one you assigned at Design-time. In fact, it's not the same instance, so it has to get the structure again.[/quote]
        Then why bother looping through the data source and adding code for the structure if its just going to be ignored at run time?  Also, since I do know that the structure will be the same, shouldn't it be possible to turn this functionality off and tell the grid to assume the structure matches?

        [quote user="[Infragistics] Mike Saltzman"]But I have never seen this cause any significant performance issue when MaxBandDepth is set to a reasonable number, and 5 is certainly reasonable. [/quote]
        Again, this represents a project plan task list.  The tasks has a collection of parent tasks, predecessor tasks, and user resources assigned (which each have their collection of tasks).  The grid steps through each one up to five levels deep creating more than 140 bands.  Only the task collections would be populated and viewed through the grid, the rest are set to not be visible (although they would be populated and used elsewhere).

        [quote user="[Infragistics] Mike Saltzman"]It's hard to guess without knowing more about your application. But I can tell you that the grid will not load child rows by default, so only the root-level rows of the grid should be created initially[/quote] 
        The delay is happening without any data loaded in the collection.  When debugging, the code appears to be pulling property names and metadata.  I have to get past this performance bottleneck before I can even start working with the actual data.

         

      • 0
        Mike Saltzman
        Mike Saltzman answered on Jun 12, 2009 2:41 PM

        [quote user="jbailey@baileysw.com"]Then why bother looping through the data source and adding code for the structure if its just going to be ignored at run time?[/quote]

        Because it's not "ignored" at run-time. When the grid's DataSource is set at run-time, the grid needs to examine the data structure it is being bound to to determine if the current layout in the grid matches up. If it does, then the grid uses the existing layout. If not, then the grid throws away the layout in favor of the new data structure.

        [quote user="jbailey@baileysw.com"]Also, since I do know that the structure will be the same, shouldn't it be possible to turn this functionality off and tell the grid to assume the structure matches?[/quote]

        I suppose that might be possible. You should Submit a feature request to Infragistics.

        The problem is, what happens if you specify that the grid should use the existing layout and the layout doesn't actually match exactly? The grid would probably have to raise an exception at that point.

        [quote user="jbailey@baileysw.com"]Again, this represents a project plan task list.  The tasks has a collection of parent tasks, predecessor tasks, and user resources assigned (which each have their collection of tasks).  The grid steps through each one up to five levels deep creating more than 140 bands.  Only the task collections would be populated and viewed through the grid, the rest are set to not be visible (although they would be populated and used elsewhere).[/quote]

        I think you might not be using the right terminology here. It sounds to me like you have 5 bands, not 140. A band is like a table or a relation. Each island of Data is not a band.

        If you have 5 bands and your application is experiencing serious performance problems, then something else is probably wrong. Perhaps there is some other area of the code that is inefficient or you are running on a particulatly slow machine. Or perhaps you data source is not an efficient one.

        How long is the delay, exactly?

        What kind of data source are you using for the grid?

        As a test, what happens if you use an UltraDataSource component and set up the same basic structure and bind that to the grid? Does the same delay occur? If so, then it's probably just the normal processing of the DotNet BindingManager. If not, then it indicates some inefficiency in the DataSource, itself. In which case, you might want to consider using an UltraDataSource in on-demand mode as a sort've intermediary between the grid and the data source.

      • 0
        John
        John answered on Jun 16, 2009 7:43 PM

        [quote user="[Infragistics] Mike Saltzman"]The problem is, what happens if you specify that the grid should use the existing layout and the layout doesn't actually match exactly[/quote]
        If the layout at run time isn't matching what I designed against I've got bigger problems than the grid raising an error, I've got a delta between my user interface and my business objects interfaces.  This will likely create unpredictable results across various portions of the application. 

        [quote user="[Infragistics] Mike Saltzman"]I think you might not be using the right terminology here. It sounds to me like you have 5 bands, not 14[/quote]
        The bands are listed in the designer as an array.  The last band listed in the designer is Band[140].  Unless I am missing something, that means there are 140 bands.

        [quote user="[Infragistics] Mike Saltzman"]

        How long is the delay, exactly?

        [/quote]
        The delay is about 15 – 30 seconds.

        [quote user="[Infragistics] Mike Saltzman"]

        What kind of data source are you using for the grid?

        [/quote]
        I am using a business entity object generated with .Net tiers.

        I'm not sure how you would use the UltraDataSource as an intermediary.  What I ended up doing was basically abandoning the designer (it seemed to have lots of problems after the second level anyway) and wrote code to create the five levels of bands myself in the control constructor.  This resolved the delay.  Apparently creating all the bands I wasn't using was what was causing the delay.

    • 0
      Mike Saltzman
      Mike Saltzman answered on Jun 11, 2009 4:07 PM

      [quote user="ADASDev"]We Have noticed that with 40 rows their is a marked delay from when the new value list is returned and when we set the e.Cell.ValueList property to when it display's to the user.[/quote]

      Are you talking about 40 rows in the ValueList? Or 40 rows in the grid?

      If you mean the ValueList has 40 items, then this should be practically instantaneous and I can't see how it could possibly cause a performance problem, unless there are exceptions occuring.

      If you mean 40 rows in the grid and your ValueList has a lot more rows, then the grid has to search the list to find the matching value in order to convert the DataValue into the corresponding DisplayText. There's no way around this.

      Perhaps instead of assigning a new ValueList to each cell, you should just use a Filtered UltraDropDown that contains a list of all possible values.

      There is an article describing this technique here.

      • 0
        Richard
        Richard answered on Jun 11, 2009 4:23 PM

        I was refereeing to the 40 rows in the grid, I will look into Filtered UltraDropDown. and the original article some useful hints.

        Cheers 

         

      • 0
        Mike Saltzman
        Mike Saltzman answered on Jun 11, 2009 4:27 PM

        [quote user="ADASDev"]I was refereeing to the 40 rows in the grid, I will look into Filtered UltraDropDown. and the original article some useful hints.[/quote]

        So how many items are on the ValueList?

        It occurs to me that if you are changing the ValueList on the cell, then the Value in that cell is unlikely to be valid for the new list. So perhaps what you should do is set the Value of the cell to null or DBNull.Value before you change the ValueList.

        I'm not entirely sure that will help, but it's worth a shot. 🙂

  • 0
    [Infragistics] Vince McDonald
    [Infragistics] Vince McDonald answered on Oct 23, 2009 4:24 PM

    In the interest of keeping the information here helpful, on-topic, and easier to follow, I'm locking this thread.  If we find the need to edit the information here, or to add to it, we'll unlock the thread to make these changes.

    For anyone who has additional questions, comments, or discussions regarding the WinGrid Performance Guide, please feel free to create a new thread, and use a hyperlink to refer back to this one.

    Thank you, everyone!

  • You must be logged in to reply to this topic.
Discussion created by
Favorites
Replies
Created On
Last Post
Discussion created by
Mike Saltzman
Favorites
0
Replies
48
Created On
Oct 23, 2009
Last Post
16 years, 4 months ago

Suggested Discussions

Created by

Created on

Oct 23, 2009 4:24 PM

Last activity on

Feb 19, 2026 1:45 PM