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
13 Answers, 1 is accepted
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
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 >>
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.
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
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:
- http://www.telerik.com/forums/bestfit-performance
- http://www.telerik.com/forums/bestfitcolumns-and-autosize-or-fill
I hope this helps. Should you have further questions please do not hesitate to write back.
Regards,
Hristo Merdjanov
Telerik by Progress
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()
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
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,
Thank you for writing.
The RadGridView.BestFitColumns method receives a BestFitColumnMode parameter determining which cells will be measured. The available options are DisplayedDataCells, HeaderCells, FilterCells, SummaryRowCells, SystemCells, DisplayedCells, 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
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.
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).
sorry, forgot the link in last post:
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