BestFit method not working as expected

14 posts, 0 answers
  1. Leonardo
    Leonardo avatar
    7 posts
    Member since:
    Apr 2009

    Posted 26 Aug 2011 Link to this post

    Hi,

    I'm trying to use the BestFit method dynamically to resize the column width property as the largest word in my DataSet in one column specific. But when I use this method, the application fit the column as the largest word that I can see, and if I slide the scroll down, some words in the grid column is truncated. 

    How can I do to display all my grid data with no truncate words?

    Regards
  2. erwin
    erwin avatar
    358 posts
    Member since:
    Dec 2006

    Posted 29 Aug 2011 Link to this post

    Hi Leonardo

    The function works as documented for all visible rows. I guess that telerik chose to limit the measuring to visible rows because of performance reasons.

    Limiting sizing to visible rows has other advantages, when a non-visible cell is considerably wider than all visible cells of the same column that would otherwise lead to waste of space for the displayed portion of the grid.

    If you know your data (and formatting rules) you can always set the width of a column manually, by measuring a typical string with the current font of the grid.

    Erwin
  3. UI for WinForms is Visual Studio 2017 Ready
  4. Alexander
    Admin
    Alexander avatar
    306 posts

    Posted 31 Aug 2011 Link to this post

    Hello guys,

    Thank you, Erwin, for the provided explanations and comments. BestFit for all cells of a particular column could be implemented by creating cell element for each data cell of the column and measuring this element. The following code snippet demonstrated one approach to achieve it:
    private void BestFitAllCells(GridViewColumn column)
    {
        IVirtualizedElementProvider<GridViewRowInfo> rowProvider = this.radGridView1.TableElement.RowElementProvider;
        IVirtualizedElementProvider<GridViewColumn> cellProvider = this.radGridView1.TableElement.ColumnScroller.ElementProvider;
     
        float width = 0;
        foreach (GridViewRowInfo dataRow in this.radGridView1.Rows)
        {
            GridRowElement row = rowProvider.GetElement(dataRow, null) as GridRowElement;
            row.InitializeRowView(this.radGridView1.TableElement);
            row.Initialize(dataRow);
            row.UpdateInfo();
     
            this.radGridView1.TableElement.Children.Add(row);
            row.ResetLayout(true);
     
            GridVirtualizedCellElement cell = cellProvider.GetElement(column, row) as GridVirtualizedCellElement;
            cell.Attach(column, row);
     
            cell.SetContent();
            cell.UpdateInfo();
     
            row.Children.Add(cell);
     
            GridHeaderCellElement headerCell = cell as GridHeaderCellElement;
            if (headerCell != null)
            {
                headerCell.UpdateArrowState();
            }
     
            cell.ResetLayout(true);
            width = Math.Max(width, this.GetCellDesiredWidth(cell));
     
            row.Children.Remove(cell);
            this.radGridView1.TableElement.Children.Remove(row);
     
            this.Detach(cellProvider, cell);
            this.Detach(rowProvider, row);
        }
     
        column.Width = (int)width;
    }
     
    private float GetCellDesiredWidth(GridCellElement cell)
    {
        cell.Measure(new SizeF(float.PositiveInfinity, float.PositiveInfinity));
        return cell.DesiredSize.Width;
    }
     
    private void Detach(IVirtualizedElementProvider<GridViewColumn> elementProvider, GridCellElement cell)
    {
        GridVirtualizedCellElement virtualizedCell = cell as GridVirtualizedCellElement;
     
        if (virtualizedCell != null)
        {
            elementProvider.CacheElement(virtualizedCell);
            virtualizedCell.Detach();
            return;
        }
     
        cell.Dispose();
    }
     
    private void Detach(IVirtualizedElementProvider<GridViewRowInfo> elementProvider, GridRowElement row)
    {
        GridVirtualizedRowElement virtualizedRоw = row as GridVirtualizedRowElement;
     
        if (virtualizedRоw != null)
        {
            elementProvider.CacheElement(virtualizedRоw);
            virtualizedRоw.Detach();
            return;
        }
     
        row.Dispose();
    }

    I hope it helps.

    Best regards,
    Alexander
    the Telerik team

    Thank you for being the most amazing .NET community! Your unfailing support is what helps us charge forward! We'd appreciate your vote for Telerik in this year's DevProConnections Awards. We are competing in mind-blowing 20 categories and every vote counts! VOTE for Telerik NOW >>

  5. Abba
    Abba avatar
    22 posts
    Member since:
    Jan 2013

    Posted 24 Sep Link to this post

    This is not true, or something is not working correct.
    I do not find that it is only using the visible columns.  Or there is issue with this.

    Here is simple test:
    I load 1000 rows of data from a SQL table without bestfit.  It is fast.
    I load same 1000 rows with bestfit.  It takes awhile.
    I load from same table, but with 5000 rows and with bestfit.  It takes much longer!

    If the bottle next is the bestfit (which it clearly is), and if it only uses the visible rows, the time difference between 1000 and 5000 rows should be very little if any.  But it is huge.

    Either this is a bug that needs to be addressed, or it is not correctly documented/supported.   I have tried with 2013 Q3 and well as 2015 Q3 (awhile back).

    Also, I will state again, this bestfit is VERY needed, yet VERY VERY slow (unuseable). 
    This has been an ongoing issue with RadGridView that just doesn't seem to get resolved.  I think it is false advertising because in your demos it shows loading millions of rows, yet if you put bestfit on it'll take over 10 seconds just to load 10k.  You could never get near 1million and still have a usable application.
    I really don't see what is so hard about getting the visible rows calculating the widths and applying them.  It should not take as long as it does.

  6. erwin
    erwin avatar
    358 posts
    Member since:
    Dec 2006

    Posted 24 Sep in reply to Abba Link to this post

     

    Did you load the grid using deferred refresh? To my experience that can make a huge difference.

    I usually let the user choose the width (and other aspects of the layout like column order) they like and use the Load/Save Layout. Another approach I sometimes use is to calculate the width of the probably largest column myself. Since the application knows the data it displays, it can make a guess that works most of the time.

    Regards Erwin

     

     

  7. Hristo
    Admin
    Hristo avatar
    714 posts

    Posted 26 Sep Link to this post

    Hi guys,

    Thank you for writing.

    When your grid is data bound to a great number of items, calling the BestFit method with the BestFitColumnMode.AllCells parameter may indeed cost an additional time. The reason for this is that all of the cells need to be iterated, measured and sized. I can suggest best fitting the columns once you have set the data source.

    You can also check the following forum threads discussing a similar question:  Additionally, you may consider displaying a waiting bar indicating that the grid is performing a long running operation: http://www.telerik.com/support/kb/winforms/track-and-status/details/indicating-progress-in-applications-that-have-their-primary-ui-thread-busy.

    I hope this helps. Should you have further questions please do not hesitate to write back.

    Regards,
    Hristo Merdjanov
    Telerik by Progress
    Check out the Windows Forms project converter, which aids the conversion process from standard Windows Forms applications written in C# or VB to Telerik UI for WinForms. For more information check out this blog post and share your thoughts.
  8. Abba
    Abba avatar
    22 posts
    Member since:
    Jan 2013

    Posted 26 Sep Link to this post

    Thank you both for quick reply.

    1-Erwin: what do you mean by deferred refresh?  If you mean begin/end update, yes it is wrapped.  The problem with the layout is i am running queries with different data in the same grid.  for example, sometimes it is from one table, sometimes from another.
    I will also mention that the begin/end update seems to have issue as i have used it in other parts of code and it was noticable slower with it on.  seems strange, but i confirmed it.  But in this part, it is fine

    2-Hristo: why does all cells need to be iterated, measured, sized instead of just the visible ones?  This is also contrary to what was stated earlier in the thread.  Can someone get to the bottom of this and determine which way it works?  It seems like it would be faster to only check the visible ones, but it doesn't seem to work like that.  As I mentioned I am running the same query in the same size results window (same amount of visible rows: 25) with a big difference in time between 1000 and 5000 rows.
    I also only bestfit after the datasource is set (as you mentioned).

    I have also tested just showing 1 row visible and it is taking longer for 1000 vs 3000.  Again confirming my theory that it is not running only on the visible and indeed is running all rows.  A waste.  If anything there should be a setting for each, but default to only visible.

    SSMS is my comparison and it is MUCH faster and also bestfits.  Why does this take so much more time?  It should be able to match that performance at least.  and it is close to same speed without the bestfit.  

    I hesitate to return anything over 500 rows because of the delay.  But when I need to query a lot, this becomes a bottle neck.

    My only last test (which means i now have to be your developer) is to run a calc on the first x cols and set the width each time to see if that is faster.  I feel it will be, especially noticeable on rows over 1000.
    Again, showing that this is an ongoing issue (your links show since 2008) with performance.

    Here is my code.  I hope someone could look into and finially resolve so i don't have todo each work arounds.

    'set the datasource
    GridView.DataSource = Nothing
    GridView.DataSource = GetDataTable()

    'set bestfit
    GridView.TableElement.BeginUpdate()
    GridView.MasterTemplate.BestFitColumns(BestFitColumnMode.AllCells)
    GridView.TableElement.EndUpdate()
  9. erwin
    erwin avatar
    358 posts
    Member since:
    Dec 2006

    Posted 26 Sep in reply to Abba Link to this post

     

    I'm assuming you are using auto-generated columns. I usually use code like this (pseudocode): 

    To my experience, when using AutoGenerated columns, it's better not to re-assign a new DataTable with every Refresh, but to just reload the existing DataTable. The grid gets notified by the change in the DataTable and updates itself accordingly.

    Also it's key to have the assignment of the datasource within the Begin/EndUpdate Block.

    With this construct I routinely load 10'000 rows with dozens of columns in under 1 sec, including the sql server database query execution time.

     

    using (gridView.DeferRefresh())  // (calls BeginUpdate())
    {
        if (dataTable = null)
        {
            // initial load
            dataTable = datalogic.GetDataTable();
             
            gridView.DataSource = dataTable;
     
            if(layoutpersistence.HasSavedLayout(gridView))
            {
                gridView.LoadLayout(layoutpersistence.GetSavedLayout(gridView));
            }
            else
            {
                gridView.BestFitColumns();
            }
        }
        else
        {
            // refresh, do not change grid layout and do not re-assign the datasource to the grid
            datalogic.UpdateDataTable(dataTable);
        }
    } // implicitely calls EndUpdate() even if the datalogic errs out 

     

    regards

    Erwin

     

     

  10. Abba
    Abba avatar
    22 posts
    Member since:
    Jan 2013

    Posted 27 Sep Link to this post

    Thank you again for getting back to me so quick.

    First, sorry for being cranky.

    Second, I did miss something...apparently there is an option in the bestfit for displayed versus all.  When I set this, it is faster, and on the larger data sets as well.

    Third, I will have to try the update method.  I have used it before on another grid in the application with poor results (and from what i recall issues. do i have to reset the master template?  and/or the gains weren't seen noticed).  It was a self referencing (hierarchy) grid though.

    Fourth, can you send the update method code or pseudo so i can make sure it is correct.  or if it is in another thread/documentation.  or if it is just updating the datasource (meaning, setting the query result into the underlying datatable is all).

     

    Regards,

  11. Hristo
    Admin
    Hristo avatar
    714 posts

    Posted 27 Sep Link to this post

    Hi guys,

    Thank you for writing.

    The RadGridView.BestFitColumns method receives a BestFitColumnMode parameter determining which cells will be measured. The available options are DisplayedDataCellsHeaderCellsFilterCellsSummaryRowCellsSystemCellsDisplayedCells, and AllCells. The DisplayedCells is indeed a good option when you have a large dataset.

    Abba, the provided by Erwin approach is valid. Please also note that it is not necessary to reset the data source of the grid as long as the object to which it is bound notifies it for the update. The various ways to data bind RadGridView are discussed in the following section of the documentation: Populating with Data.

    I hope this helps. Should you have further questions please do not hesitate to write back.

    Regards,
    Hristo Merdjanov
    Telerik by Progress
    Check out the Windows Forms project converter, which aids the conversion process from standard Windows Forms applications written in C# or VB to Telerik UI for WinForms. For more information check out this blog post and share your thoughts.
  12. Abba
    Abba avatar
    22 posts
    Member since:
    Jan 2013

    Posted 28 Sep Link to this post

    Thanks.  I looked in that documentation section and i see ways to bind, but that is not the issue.  Is there specific section with specific code showing this update and notify?  Am I missing it?  Is it just a matter of changing the datatable?  What about:
    Gridview.MasterTemplate.Reset()
    Gridview.MasterTemplate.Refresh()
    ?

    I remember seeing such technique in a thread on here.  And I believe i tried, but ran into issues.  whether updating or something. That is why i had to resort to the reapplying.  
    It is possible that it was the version I am on and it was improved later on.
    If you have a sample project already built, that would be great.  No need to create if not.
    If you feel there is a performance gain to it (or it is the more correct way), I can try again.

  13. Abba
    Abba avatar
    22 posts
    Member since:
    Jan 2013

    Posted 28 Sep Link to this post

    By the way,

    This seems outdated.  At the bottom it is setting bestfit on each column (not mastertemplate) and without begin/end update would be working each loop (if i'm not mistaken).

  14. Abba
    Abba avatar
    22 posts
    Member since:
    Jan 2013
  15. Hristo
    Admin
    Hristo avatar
    714 posts

    Posted 29 Sep Link to this post

    Hello Abba,

    Thank you for writing.

    Starting with your last post, calling the BestFit method for each of the columns individually basically achieves the same result as calling the BestFitColumns of the grid. Please note that the BestFit method can be called for a single column if needed and that it also respects the AutoSizeMode property set on the column.

    Considering your other question regarding the binding mechanism, as I said previously the grid will automatically reflect any changes in your data object as long as it is notified about the changes. The Reset method called on the master template sets the data source to null and additionally clears all settings like templates or relations. Please check the following documentation article discussing how changes in the data objects can be reflected in the grid: http://docs.telerik.com/devtools/winforms/gridview/populating-with-data/reflecting-custom-object-changes-in-rgv.

    I hope this information is useful. Should you have further questions please do not hesitate to write back.

    Regards,
    Hristo Merdjanov
    Telerik by Progress
    Check out the Windows Forms project converter, which aids the conversion process from standard Windows Forms applications written in C# or VB to Telerik UI for WinForms. For more information check out this blog post and share your thoughts.
Back to Top
UI for WinForms is Visual Studio 2017 Ready