This is a migrated thread and some comments may be shown as answers.

Resize Column to fit it's contents

45 Answers 2642 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Waleed Seada
Top achievements
Rank 2
Waleed Seada asked on 19 Nov 2009, 05:46 AM
Dear All,

I have a gridview control with more than 50 item, how can I display them in the gridview with there full width.
I have tried AutoResizeMode, but it shrink all of them in the viewable area of the grid, I need that all columns
get resized to it's contents regardless of it's visuallity.

Is this possible...

Best regards

45 Answers, 1 is accepted

Sort by
0
Jack
Telerik team
answered on 23 Nov 2009, 09:10 AM
Hi Waleed Seada,

Thank you for contacting us. I am not sure that I understand your question correctly. However, you can control the column width by using AutoSizeColumnsMode property. When it is set to Fill all columns are resized to fit to the available grid area. When it is set to None, its width is controlled by GridViewColumn.Width property. You can call MasterGridViewTemplate.BestFitColumns method to let RadGridView calculate the optimal width. I hope this helps, if you have further questions, please write me back.

Regards,
Jack
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
0
Joshua Teter
Top achievements
Rank 1
answered on 09 Mar 2010, 11:20 PM
I am having the same issue.

Problem: I have a RadGridView that has 30 columns and I want every column to auto size to where the column's content is displayed fully. However, the BestFitColumns mode resizes the columns to where all 30 columns can be seen without scrolling but this makes their content cut off. I want each column to be fit to see it's content even if that means that the user must scroll to the right to see all of the columns. The Fill Mode does the same as BestFitColumns in that it resizes the columns so that they are visible within the grid (with no scroll bars)

I have attached two files, StandardTelerikLayout.png shows how the fields are displayed. DesiredTelerikLayout.png shows how I need them to show (I got them to show like that by manually double-clicking the header lines to force each column to size-to-fit.). Notice the second picture has a scroll bar, so each column isn't visible within the grid without scrolling but instead each column's size is changed to fits it's own contents.

Thanks!

-Josh
0
Jack
Telerik team
answered on 10 Mar 2010, 01:16 PM
Hi Joshua Teter,

I am not sure that I understand the issue correctly. From what you described, I think that the best option is to call BestFitColumns method. Please send me your application, this will allow me to research the issue further. I am looking forward to your reply.

Regards,
Jack
the Telerik team

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
0
Roland
Top achievements
Rank 1
answered on 17 Jun 2010, 10:55 PM
Hello,

What I need is to be able to set one column to Fill and all others fixed width.

How do I do that ?
0
Jack
Telerik team
answered on 23 Jun 2010, 11:23 AM
Hi Roland,

You can achieve this by setting MinWidth and MaxWidth properties for all columns that should have fixed size and by using fill mode. Consider the sample below:

for (int i = 0; i < this.radGridView1.Columns.Count - 1; i++)
{
    this.radGridView1.MasterGridViewTemplate.Columns[i].MinWidth = 60;
    this.radGridView1.MasterGridViewTemplate.Columns[i].MaxWidth = 60;
    this.radGridView1.MasterGridViewTemplate.Columns[i].Width = 60;
}
 
this.radGridView1.MasterGridViewTemplate.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;

 

Best wishes,
Jack
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Phillip Foster
Top achievements
Rank 1
answered on 16 Jul 2010, 09:29 PM
Hi. I want to achieve a similar effect, but i don't want a fixed size on the other columns, because i don't know what the width is going to be. 

I want to be able to say something like :
dataGridView.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
dataGridView.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
dataGridView.Columns[2].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
dataGridView.Columns[3].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;


thus making the first 3 columns fit to the size of the largest text, and the forth to fill the rest of the grid. 

Is this possible with the RadGridView?

Thanks. 
0
Jack
Telerik team
answered on 20 Jul 2010, 06:40 AM
Hi Phillip Foster,

This feature is not available in RadGridView. However, we plan to extend our column sizing modes and I will add this as a feature request. It will be considered when planning our future versions and if more people request the same feature, we will raise its priority.

Should you have any other questions, don't hesitate to ask.

Sincerely yours,
Jack
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Deborah
Top achievements
Rank 1
answered on 22 Sep 2010, 09:06 PM
What Phillip requested is what I am trying to do as well.

I have financial data and a "description" column. I want to ensure that the full contents of the financial data are shown and grow/shrink the "description" column so needed. If the user resizes the form, the financial data columns should stay the same size (fit to contents) and the "description" column show grow or shrink.

So there is no work around for this at this point in time?
0
Emanuel Varga
Top achievements
Rank 1
answered on 24 Sep 2010, 03:58 PM
Hello everyone,

Sadly there is a strange thing in the radGridView1.Columns[0].BestFit(); in my tests if you have a pyramidal structure for the data contained in the column, let's say in column 0 we have 10 rows and there is a letter on the first, row, 2 on the second, and so on, if you change the size of the column to cover most of the text in the column and create a button that calls just BestFit() on the column you will see that it takes more than a few presses until all the content is visible...

Deborah, if you just have one column that you always need at maximum width, on data binding complete,  you could just go trough all of the rows, get the maximum string size for that column and based on that calculate the min, max & width of that column and just like Jack said, set the grid
this.radGridView1.MasterGridViewTemplate.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;

This is not a clean solution, but it passes as a workaround until a fix will be released...

void radGridView1_DataBindingComplete(object sender, Telerik.WinControls.UI.GridViewBindingCompleteEventArgs e)
        {
            var maxString = string.Empty;
            foreach (var row in radGridView1.Rows)
            {
                var value = row.Cells[0].Value.ToString();
                maxString = maxString.Length > value.Length ? maxString : value;
            }
 
            var minWidth = radGridView1.CreateGraphics().MeasureString(maxString, radGridView1.Font);
            radGridView1.Columns[0].MinWidth = (int)minWidth.Width + 5;
            radGridView1.Columns[0].MaxWidth = (int)minWidth.Width + 5;
            radGridView1.Columns[0].Width = (int)minWidth.Width + 5;
        }

Hope this helps, and hope that the problem with BestFit() on the column will be fixed soon.

Best Regards,
Emanuel Varga
0
Bernd Mueller
Top achievements
Rank 1
answered on 24 Sep 2010, 04:23 PM
Hello all,

that problem was troubling me as well and i would like to join the feature request fraction to raise the priority of the task.
Thank you and have a nice weekend!

Bernd
0
Deborah
Top achievements
Rank 1
answered on 24 Sep 2010, 04:59 PM
There is another issue I see. I have a bound grid of customers and a bound grid of data associated with the customer. As the user picks another customer, the second grid is rebound.

When the page first comes up, the columns correctly fill the grid. However, when I rebind the second grid, the spacing is no longer correct. It looks like it may be providing space for a scroll bar? (But my grid is a standard # of rows and columns, so there should never need to be a scroll bar.)

Bottom line, it leaves a white column of empty space between the last column of data and the edge of the grid which is not acceptable to my customer for their product. Again, this only happens AFTER a rebind. It works fine when it is first displayed on the screen.

The only way around this I found was to clear the grid columns and rebuild them (instead of just rebinding the data in the columns.)

So if you could look into this one as well I would appreciate it.

Thanks!
0
Jack
Telerik team
answered on 24 Sep 2010, 06:18 PM
Hello Deborah,

Thank you for this explanation. I understand what you want to achieve. You should use the AutoSizeColumnsMode set to Fill. Before setting this property set the desired column size for the financial column and set its AllowResize property to false. This will fix it size and it will not change when RadGridView grows/shrinks. Here is a sample:

this.radGridView1.Columns["Value"].Width = 120;
this.radGridView1.Columns["Value"].AllowResize = false;
this.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;

I hope this helps. If you have any further questions, do not hesitate to ask.

Best wishes, Jack
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Deborah
Top achievements
Rank 1
answered on 25 Sep 2010, 12:25 AM
Thank you for getting back to me so quickly.

We are getting closer, but that won't quite work for me. The user can change the font for the application (just like the little font size area in IE). So if the font changes, the grid columns do need to resize. With my original settings, this was working fine (until I rebound the grid). With these new settings, that no longer works.

My current work around is just to delete all of the columns and rebuild the grid, which works, but can't be all that efficient.

Thanks again!
0
Emanuel Varga
Top achievements
Rank 1
answered on 25 Sep 2010, 10:49 AM
Hello Deborah,

Did you read my reply from earlier?, there, on data binding complete, you will calculate the maximum size of the column based on it's content using the Font on the grid, when the user changes the font, the font on the grid will change also, so this will continue to work, try it and please let me know....

Just put that in a method and call it also when the user changes the font, register for the FontChanged event and call it from there, it should do what you need

Best Regards,
Emanuel Varga
0
Deborah
Top achievements
Rank 1
answered on 28 Sep 2010, 09:15 PM
Yes, I have tried just about everything. I really think that there is a problem with the grid because it continues to look like it is saving a space for the scroll bar.

When I added code to hard-code the column width, it is even more apparent that it is attempting to save that space. I attached a screen shot.
0
Emanuel Varga
Top achievements
Rank 1
answered on 29 Sep 2010, 07:12 AM
Hello Deborah,

I've tried to reproduce your issue, by using the same 2 grids one for data, and one for details that loads when CurrentRowChanged in the main grid.

I will attach here the test I've made, please let me know what is different in your scenario.

namespace TestGridSourceDetails
{
    using System;
    using System.ComponentModel;
    using System.Text;
    using System.Windows.Forms;
    using Telerik.WinControls.UI;
 
    public partial class Form1 : Form
    {
        private RadGridView radGridViewMain;
        private RadGridView radGridViewChild;
 
        public Form1()
        {
            InitializeComponent();
            this.Size = new System.Drawing.Size(800, 600);
            this.Load += new EventHandler(Form1_Load);
        }
 
        void Form1_Load(object sender, EventArgs e)
        {
            radGridViewMain = new RadGridView();
            radGridViewMain.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
            radGridViewMain.CurrentRowChanged += new CurrentRowChangedEventHandler(radGridViewMain_CurrentRowChanged);
            radGridViewMain.DataSource = new TestsCollection(10);
            radGridViewMain.Dock = DockStyle.Left;
            radGridViewMain.Size = new System.Drawing.Size(this.Width / 2 - 10, this.Height);
 
            radGridViewChild = new RadGridView();
            radGridViewChild.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
            radGridViewChild.Dock = DockStyle.Right;
            radGridViewChild.Size = new System.Drawing.Size(this.Width / 2 - 10, this.Height);
 
            this.Controls.Add(radGridViewMain);
            this.Controls.Add(radGridViewChild);
        }
 
        void radGridViewMain_CurrentRowChanged(object sender, CurrentRowChangedEventArgs e)
        {
            var currentItem = (Test)radGridViewMain.CurrentRow.DataBoundItem;
            radGridViewChild.DataSource = new TestDataCollection(currentItem.Id, 10);
        }
    }
 
    #region Helpers
 
    public class Test
    {
        public Test(int id, string name)
        {
            this.Id = id;
            this.Name = name;
        }
 
        public int Id
        {
            get;
            set;
        }
 
        public string Name
        {
            get;
            set;
        }
    }
 
    public class TestData
    {
        public TestData(int id, int testId, string name)
        {
            this.Id = id;
            this.TestId = testId;
            this.Name = name;
        }
 
        public int Id
        {
            get;
            set;
        }
 
        public int TestId
        {
            get;
            set;
        }
 
        public string Name
        {
            get;
            set;
        }
    }
 
    public class TestsCollection : BindingList<Test>
    {
        public TestsCollection(int noItems)
        {
            for (int i = 0; i < noItems; i++)
            {
                this.Add(new Test(i, RandomString.GetRandomString(DateTime.Now.Millisecond, new Random(7).Next(10, 20))));
            }
        }
    }
 
    public class TestDataCollection : BindingList<TestData>
    {
        public TestDataCollection(int testId, int noItems)
        {
            for (int i = 0; i < noItems; i++)
            {
                this.Add(new TestData(i, testId, RandomString.GetRandomString(DateTime.Now.Millisecond, new Random(7).Next(10, 20))));
            }
        }
    }
 
    internal static class RandomString
    {
        public static string GetRandomString(int initialSeed, int size)
        {
            StringBuilder builder = new StringBuilder();
            Random random = new Random(initialSeed);
            char ch;
            for (int i = 0; i < size; i++)
            {
                ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
                builder.Append(ch);
            }
 
            return builder.ToString();
        }
    }
 
    #endregion Helpers
}

Best Regards,
Emanuel Varga
0
Jack
Telerik team
answered on 01 Oct 2010, 07:44 AM
Hi Debora, I understand your concerns and we will consider implementing this feature in a future version of RadGridView. Please, check the solution from Emanuel. I think that it will fit in your case. If you need further assistance, I will be glad to help.
 
Sincerely yours,
Jack
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Deborah
Top achievements
Rank 1
answered on 16 Oct 2010, 08:07 PM
After much more testing of this ... it appears that the problem is with BestFitColumns. If I add BestFitColumns to any of my grids that currently work, I then get that same extra space (see my prior screen shot) that looks like the grid is saving space for a scroll bar.

If I take BestFitColumns out, it appears to be stopping this behavior.
0
Deborah
Top achievements
Rank 1
answered on 16 Oct 2010, 08:13 PM

I decided to try to implement this code that you provided using MeasureString. It does not work in the following cases:

  • The cell is wrapped (it attempts to fit the entire contents instead of allowing the wrap to occur)
  • The cell is formatted (it ignores the formatting, causing the size to be inaccurate)
  • The cell's header is longer than its text.
  • The cell's header length is not longer, but its measure size is (example: phone numbers since numbers are often narrower than letters in the header)
  • The cell is bound to a combobox (it uses the Value and not the DisplayValue).
    • I tried using the .Text property, but it does not appear to support that like the ASP.Net version seems to have.

I have found work arounds for the first four, but am really stuck on the last one. Here is my code:

Private Sub SCStarDataGrid_DataBindingComplete(ByVal sender As Object, ByVal e As Telerik.WinControls.UI.GridViewBindingCompleteEventArgs) Handles Me.DataBindingComplete
    If Me.Rows.Count > 0 Then
        Dim largestString As String
        For Each col In Me.Columns
            ' For any wrap columns, set a default minimum width
            If col.WrapText = True Then
                col.MinWidth = 20
                col.Width = 20
            Else
                ' Start with the header text
                largestString = col.HeaderText
                For Each row In Me.Rows
                    Dim cellValue = If(row.Cells(col.Index).Value Is Nothing, String.Empty, row.Cells(col.Index).Value.ToString)
                    ' Format the cell value based on the provided format string
                    If Not String.IsNullOrWhiteSpace(col.FormatString) Then
                        ' The date formatting only works if the data type is a date, so try to convert it.
                        Dim cellDate As DateTime
                        If DateTime.TryParse(cellValue, cellDate) Then
                            cellValue = String.Format(col.FormatString, cellDate)
                        Else
                            cellValue = String.Format(col.FormatString, cellValue)
                        End If
                    End If
                    largestString = If(largestString.Length >= cellValue.Length, largestString, cellValue)
                Next
                Dim columnSize = Me.CreateGraphics().MeasureString(largestString, Me.Font)
                Dim columnHeaderSize = Me.CreateGraphics.MeasureString(col.HeaderText, Me.Font)
                Dim columnWidth = If(columnSize.Width > columnHeaderSize.Width, columnSize.Width, columnHeaderSize.Width)
                col.MinWidth = CType(columnWidth, Integer) + 5
                col.Width = CType(columnWidth, Integer) + 5
            End If
        Next
    End If
End Sub


Any help would be appreciated.

0
Emanuel Varga
Top achievements
Rank 1
answered on 16 Oct 2010, 09:44 PM
Hello Deborah,

I have a solution for you, but it's not a clean one, but it will work in all possible cases, and you don't have to use that complicated calculation function, but I'm not sure if it's the cleanest way to do things, but it will work.

From the previous posts, i know you are creating a custom grid control, and this is good because this solution also requires you to hold a dictionary of strings.
The actual .Text property of a cell is just available in the CellFormatting event and in the RowFormatting event,
Please take a look at the following example:
C#
Dictionary<string, string> dictionary = new Dictionary<string, string>();
void radGridView1_CellFormatting(object sender, CellFormattingEventArgs e)
{
    var column = e.CellElement.ColumnInfo;
    var text = e.CellElement.Text;
    if (string.IsNullOrEmpty(text))
    {
        return;
    }
     
    if (dictionary[column.HeaderText].Length < text.Length)
    {
        dictionary[column.HeaderText] = text;
        column.MinWidth = (int)(this.CreateGraphics().MeasureString(text, this.Font).Width+8);
    }
}

and VB:
Private dictionary As New Dictionary(Of String, String)()
Private Sub radGridView1_CellFormatting(sender As Object, e As CellFormattingEventArgs)
    Dim column = e.CellElement.ColumnInfo
    Dim text = e.CellElement.Text
    If String.IsNullOrEmpty(text) Then
        Return
    End If
 
    If dictionary(column.HeaderText).Length < text.Length Then
        dictionary(column.HeaderText) = text
        column.MinWidth = CInt(Me.CreateGraphics().MeasureString(text, Me.Font).Width + 8)
    End If
End Sub

The idea here is to hold a dictionary with the column header text as the key and the largest string on that column as the value, and setting the minimum width on the column based on that value.

Please let me know what you think about this.

Best Regards,
Emanuel Varga
0
Emanuel Varga
Top achievements
Rank 1
answered on 16 Oct 2010, 09:58 PM
I forgot about the DataBindingComplete event in my previous example, where you first add the header texts to the dictionary, here is the complete code with a fixed min + max width for all the columns:

again, C#
Dictionary<string, string> dictionary = new Dictionary<string, string>();
void radGridView1_CellFormatting(object sender, CellFormattingEventArgs e)
{
    var column = e.CellElement.ColumnInfo;
    var text = e.CellElement.Text;
    if (string.IsNullOrEmpty(text))
    {
        return;
    }
 
    if (dictionary[column.HeaderText].Length < text.Length)
    {
        dictionary[column.HeaderText] = text;
        column.MaxWidth = (int)(this.CreateGraphics().MeasureString(text, this.Font).Width + 8);
        column.Width = column.MaxWidth;
        column.MinWidth = column.MaxWidth;
    }
}
 
void radGridView1_DataBindingComplete(object sender, GridViewBindingCompleteEventArgs e)
{
    var grid = sender as RadGridView;
    foreach (var column in grid.Columns)
    {
        dictionary.Add(column.HeaderText, column.HeaderText);
        column.MaxWidth = (int)(this.CreateGraphics().MeasureString(column.HeaderText, this.Font).Width + 8);
        column.Width = column.MaxWidth;
        column.MinWidth = column.MaxWidth;
    }
}

and VB:
Private dictionary As New Dictionary(Of String, String)()
Private Sub radGridView1_CellFormatting(sender As Object, e As CellFormattingEventArgs)
    Dim column = e.CellElement.ColumnInfo
    Dim text = e.CellElement.Text
    If String.IsNullOrEmpty(text) Then
        Return
    End If
 
    If dictionary(column.HeaderText).Length < text.Length Then
        dictionary(column.HeaderText) = text
        column.MaxWidth = CInt(Me.CreateGraphics().MeasureString(text, Me.Font).Width + 8)
        column.Width = column.MaxWidth
        column.MinWidth = column.MaxWidth
    End If
End Sub
 
Private Sub radGridView1_DataBindingComplete(sender As Object, e As GridViewBindingCompleteEventArgs)
    Dim grid = TryCast(sender, RadGridView)
    For Each column As var In grid.Columns
        dictionary.Add(column.HeaderText, column.HeaderText)
        column.MaxWidth = CInt(Me.CreateGraphics().MeasureString(column.HeaderText, Me.Font).Width + 8)
        column.Width = column.MaxWidth
        column.MinWidth = column.MaxWidth
    Next
End Sub

Again, please let me know if this is ok for you,

Best Regards,
Emanuel Varga
0
Emanuel Varga
Top achievements
Rank 1
answered on 18 Oct 2010, 12:40 PM
Hello again,

@Deborah i was wondering if the solution i offered helped you solve your issues?

Best Regards,
Emanuel Varga
0
Deborah
Top achievements
Rank 1
answered on 18 Oct 2010, 04:00 PM
Thank you for following up.

I am in California ... so I just got to work a few minutes ago. I will try this later this morning.

My biggest concern in just looking at the code is performance. The Formatting event is generated 100's of times.

Longer term, will you be adding a .Text or .FormattedValue property so we can access the shown value of the column outside of the Formating event?

Thanks again!
0
Emanuel Varga
Top achievements
Rank 1
answered on 18 Oct 2010, 05:30 PM
Hello again,

I know that the CellFormatting event is fired all the time, a maybe slightly faster option would be the RowFormatting event, but i am just trying to offer some workarounds that will do what you require at least until this issue will be fixed.

Please let me know if this works as expected.

Best Regards,
Emanuel Varga
0
Deborah
Top achievements
Rank 1
answered on 18 Oct 2010, 05:43 PM
Hmmm. No. I am not able to get this to work in all cases.

It seems that setting the .Width property in the DataBindingComplete causes the CellFormatting event to occur in some cases.

This is what is happening:
1) DataBindingComplete resizes the first column based on the column header size.
2) This causes the CellFormatting event on the second column, so the code generates an exception because it is trying to update the text in a Dictionary entry that has not yet been defined ("The given Key was not present in the dictionary.")

So, I assume I have several options here:
1) Modify the code in the CellFormatting to add the dictionary entry if it does not exists yet. I would also have to change the code then in DataBindingComplete to do the same thing so I don't overwrite the value set up in the CellFormatting event.
2) I need to initialize the dictionary without setting the column widths yet and instead set the column widths in the CellFormatting event.
3) ??? Other options?
0
Deborah
Top achievements
Rank 1
answered on 18 Oct 2010, 06:21 PM
I was able to get past this problem by removing all width setting code from the DataBindingComplete event and just have it resize on formatting.

I do have one other problem, however. If the user enters a large amount of text, one column can overwhelm the grid, forcing the other columns to become too small or off the screen. The client does not want the column to wrap or to scroll, but instead to show an ellipsis if the column text is too long.

So I assume I also need to add to this some calculation to ensure that the total widths of all columns does not exceed the amount of space given to the grid on the form. Any tips or links on this calculation?
0
Emanuel Varga
Top achievements
Rank 1
answered on 18 Oct 2010, 06:28 PM
Hello again, something like the windows table layout panel approach, a maximum percentage / column, set based on the importance of that column in the grid, and before setting the MinWidth, check that percentage.

And at least like that you can provide an interface for the user to customize the grid based on his/her needs, and use a Save / Load layout to load the settings for the grid, usually more customizations => happier customers.

Hope this helps, if you have any other questions or comments, please let me know,

Best Regards,
Emanuel Varga
0
Deborah
Top achievements
Rank 1
answered on 18 Oct 2010, 06:34 PM
Wow. An awful lot of work for something that already works this way in the DataGridView that somes with Visual Studio. :-(

Any code examples to kickstart this? (I have two weeks to finish the application and can't afford to spend 1 week of it getting the grids to work correctly. So any tips for how to write all of this code quickly would be appreciated.)
0
Deborah
Top achievements
Rank 1
answered on 18 Oct 2010, 06:43 PM
The first thing I am trying to do is figure out what the maximum width is that I am shooting for. When I display one of my grids, the column widths total 631. But the grid width is coming out to be 906. On the screen the columns take up 100% of the grid. Are these in different units?

Or how do I determine the maximum width I can fill with the columns?

Thanks!
0
Deborah
Top achievements
Rank 1
answered on 18 Oct 2010, 07:18 PM
In doing more research on this ... I have the AutoSizeColumnsMode set to Fill. So I assume sometime *after* the cell formatting event that the grid is resetting the widths to fill the grid?

Is there an event I can use at that point to readjust the column widths if the total width is then too large?
0
Emanuel Varga
Top achievements
Rank 1
answered on 18 Oct 2010, 08:41 PM
OK, i don't understand exactly what you are trying to say here, but i think you also misunderstood my suggestion, it goes something like this, setting a maximum percentage of the ClientSize.Width that a column may occupy, I've created a new dictionary here, but i would suggest to create a struct, or a class to hold these values, it would be cleaner, but just as a proof of concept take a look at this:

Here the max width for the ID column is 10% and for the Date is 20%

C#:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using Telerik.WinControls.UI;
 
public partial class Form1 : Form
{
    private RadGridView radGridView1;
    private TestsCollection collection = new TestsCollection(1000);
 
    public Form1()
    {
        InitializeComponent();
        this.Controls.Add(radGridView1 = new RadGridView());
        radGridView1.Dock = DockStyle.Fill;
        radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
    }
 
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        radGridView1.AddNewRowPosition = SystemRowPosition.Top;
         
        radGridView1.DataBindingComplete += new GridViewBindingCompleteEventHandler(radGridView1_DataBindingComplete);
        radGridView1.CellFormatting += new CellFormattingEventHandler(radGridView1_CellFormatting);
        SetColumnPercentage("Id", 10);
        SetColumnPercentage("Date", 20);
        radGridView1.DataSource = collection;
    }
 
    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);
        radGridView1.Refresh();
    }
 
    Dictionary<string, string> dictionary = new Dictionary<string, string>();
    Dictionary<string, int> maxColumnWidthPercentage = new Dictionary<string, int>();
 
    public void SetColumnPercentage(string headerText, int percentage)
    {
        if (maxColumnWidthPercentage.ContainsKey(headerText))
        {
            maxColumnWidthPercentage[headerText] = percentage;
            return;
        }
 
        maxColumnWidthPercentage.Add(headerText, percentage);
    }
 
    void radGridView1_CellFormatting(object sender, CellFormattingEventArgs e)
    {
        var grid = radGridView1;
        var column = e.CellElement.ColumnInfo;
        var text = e.CellElement.Text;
 
        if (string.IsNullOrEmpty(text))
        {
            return;
        }
 
        var maxPercentage = maxColumnWidthPercentage.ContainsKey(column.HeaderText) ? maxColumnWidthPercentage[column.HeaderText] : 0;
        var maxWidth = grid.ClientSize.Width * maxPercentage / 100;
        if (dictionary[column.HeaderText].Length <= text.Length && maxPercentage != 0 && column.MinWidth < maxWidth || maxPercentage != 0 && column.MinWidth > maxWidth)
        {
            dictionary[column.HeaderText] = text;
 
            var requiredWidth = (int)(this.CreateGraphics().MeasureString(text, this.Font).Width + 8);
            column.MinWidth = requiredWidth <= maxWidth ? requiredWidth : maxWidth;
            column.MaxWidth = column.MinWidth;
            column.Width = column.MaxWidth;
        }
    }
 
    void radGridView1_DataBindingComplete(object sender, GridViewBindingCompleteEventArgs e)
    {
        var grid = sender as RadGridView;
 
        var dateTimeColumm = grid.Columns[1] as GridViewDateTimeColumn;
        dateTimeColumm.FormatString = "{0:MM/dd/yy}";
        dateTimeColumm.Format = DateTimePickerFormat.Short;
 
        foreach (var column in grid.Columns)
        {
            dictionary.Add(column.HeaderText, string.Empty);
            //column.MinWidth = (int)(this.CreateGraphics().MeasureString(text, this.Font).Width + 8);
            //column.MaxWidth = column.MinWidth;
            //column.Width = column.MaxWidth;
        }
    }
}
 
public class Test
{
    public Test()
    {
    }
 
    public decimal Id { get; set; }
 
    public DateTime Date { get; set; }
 
    public string Text { get; set; }
}
 
public class TestsCollection : BindingList<Test>
{
    public TestsCollection(int noItems)
    {
        for (decimal i = 10000000000000; i < noItems + 10000000000000; i++)
        {
            this.Add(
            new Test
            {
                Id = i,
                Date = DateTime.Now.AddDays((double)(i % 17)),
                Text = "text" + i.ToString()
            });
        }
    }
}

But this will be have a great impact on performance because on size change i have to call a refresh in order for the grid to recalculate the columns.

Hope this helps, if you have any other questions or comments, please let me know,

Best Regards,
Emanuel Varga
0
Deborah
Top achievements
Rank 1
answered on 18 Oct 2010, 09:00 PM
What I was trying to say is that I am having trouble with this: grid.ClientSize.Width

In the CellFormatting event, this appears to be set to the design time size, not the runtime size.

For example, I build the form at design time and make the grid 900 wide. At runtime, the grid is set to fill the form and the form is resizable. So the user may have it set to 450 wide.

When the CellFormatting event is executed, the grid width is being calculated based on the 900 instead of the 450.

So I am currently working on shifting the calculations into the Resize event, when the grid width seems to be correctly set to 450. However, this is causing other problems in that it generates more formatting events that then resize the columns back to there original size (not the percentage).

Does this make my problem a little more clear? What happens with your code if you make the grid really small or really large at design time. Does it appear correctly at run time?
0
Emanuel Varga
Top achievements
Rank 1
answered on 18 Oct 2010, 09:05 PM
Hello Deborah,

I'm not using the designer, i prefer doing thing in code, i had a lot of problems in the past with lost values and serialization data lost, so i did everything by code, so that you can be able to test it, with just copy and paste into an empty project, if you want me to convert it to VB please let me know, but i guess you can use the telerik code converter as well.

The only thing i had to add which i don't really like is calling a refresh on the SizeChanged event, to force a recalculation of the maxWidth of the columns, but please try it for yourself and let me know.

Best Regards,
Emanuel Varga
0
Deborah
Top achievements
Rank 1
answered on 18 Oct 2010, 09:13 PM
I ended up using the technique used by the Microsoft DataGridView that allows defining a "fill" column. That is the column that will fill any remaining space after the other columns are fit to their size. (It would be REALLY great if your product provided this feature!)

My Cell Formatting then ended up like this:
Private Sub SCStarDataGrid_CellFormatting(ByVal sender As Object, ByVal e As Telerik.WinControls.UI.CellFormattingEventArgs) Handles Me.CellFormatting
    Dim column As GridViewColumn = e.CellElement.ColumnInfo
    Dim cellText As String = e.CellElement.Text
    ' If the cell has wrapped text, ignore it.
    ' If the cell is empty, ignore it.
    If Not column.WrapText AndAlso
            Not String.IsNullOrWhiteSpace(cellText) Then
        Dim columnSize = CType(Me.CreateGraphics.MeasureString(cellText, Me.Font).Width, Integer) + 5
        ' Don't set the size larger than the maximum size
        If column.MaxWidth > 0 AndAlso columnSize > column.MaxWidth Then
            columnSize = column.MaxWidth
        End If
        ' If the text in this cell is bigger than the longest string for this column, add it to the dictionary.
        If columnSizeDictionary(column.Index) < columnSize Then
            columnSizeDictionary(column.Index) = columnSize
            column.MinWidth = columnSize
            column.Width = column.MinWidth
        End If
    End If
End Sub

Notice the extra code to handle the wrapped columns and columns with a defined maximum size.

As per my prior message, I then used the resize event to resize the "fill" column if the other controls don't show all of their contents:
Dim totalColumnSize As Integer = columnSizeDictionary.Values.Sum()
If totalColumnSize > Me.ClientSize.Width Then
    Dim fillColumn = Me.Columns(FillColumnName)
    Dim fillColumnSize = Me.Width - (totalColumnSize - columnSizeDictionary(fillColumn.Index))
    columnSizeDictionary(fillColumn.Index) = fillColumnSize
    fillColumn.MaxWidth = fillColumnSize
    fillColumn.Width = fillColumn.MinWidth
End If

Notice how this just sets the maxWidth. This prevents the Formatting event from reassigning the size again.

Let me know if you see any issues with this or if there is an easier way.

Thanks again for your help.
0
Emanuel Varga
Top achievements
Rank 1
answered on 18 Oct 2010, 09:21 PM
Me for once, i would prefer to be able to say, that one column can take no more than 10% of the grid, but of course, less would be great, if you are setting the maxwidth, how will you define it in code? x pixels?
In my approach you can define a percentage for the columns you want to limit, and the rest can take / will take all of the remaining space, so you can have more than one fill column.

In my opinion it would offer a more range of usage.

Other than that, i cannot see anything wrong.

Best Regards,
Emanuel Varga
0
Deborah
Top achievements
Rank 1
answered on 18 Oct 2010, 09:31 PM
I am using this control in an application whereby 90+% of the time the user interface design rules are:
  • Set the column width to display its contents.
  • If the column width is too long and the defined text field can be wrapped, set it to wrap.
  • If the column width is too long and the defined text field cannot be wrapped (by UI design decision), truncate the field to fit.

This worked great when using the Microsoft DataGridView because you could define one column as the Fill column and it took care of everything else for you.

I don't want to add the extra work for each developer to define percentages for all of their grids when the above rules match to our application. Plus, defining the columns as percentages could cause further problems because some fields *must* appear in their entirety (per the UI design).

If these rules change at some future point, I will be back to copy your code instead.

Thanks again for all of your help!

0
Deborah
Top achievements
Rank 1
answered on 18 Oct 2010, 09:33 PM
I was going to mark several of your replies as an answer, but realized that I had hijacked someone else's thread, so I cannot access the "mark as answer" feature.

But I am *very* impressed by the level of support Telerik provides.

Thanks again!
0
Emanuel Varga
Top achievements
Rank 1
answered on 18 Oct 2010, 09:39 PM
I'm just glad to be able to help, and at least i hope i cleared some of the issues that were causing problems.

As for the support, for me it's a great way of keeping my mind sharp and helping others if and when i can. ;)

P.S. if i remember correctly, you created one or more threads with calculating widths of some specific column types, can you at please close those, and maybe redirect other people who might be interested to this thread?

Once again, always glad to help, and like always if you have any other questions or comments, please let me know,

Best Regards,
Emanuel Varga
0
Deborah
Top achievements
Rank 1
answered on 19 Oct 2010, 09:42 PM
The only problem I still have with this is scrolling.

Do you want me to start a new thread, or continue this one to explain the problem?
0
Emanuel Varga
Top achievements
Rank 1
answered on 19 Oct 2010, 09:44 PM
Hello Deborah,

Didn't i already answered the Horizontal Scroll problem in this thread ?

Or is it another scrolling issue?

Best Regards,
Emanuel Varga
0
Deborah
Top achievements
Rank 1
answered on 19 Oct 2010, 09:57 PM
I missed that you had replied to that. I'll take a look. Thanks!
0
Oliver
Top achievements
Rank 1
answered on 06 Nov 2013, 04:08 PM
Hello folks,

if you want to manually implement a glued column, you can append this function to your RadGridView's Resize event

private void FitColumns(object sender, EventArgs e)
{
    // get out if working base is not given
    var grid = sender as RadGridView;
    if (grid == null || !grid.Rows.Any()) return;
 
    // Set this property to prevent BestFitColumns() from shrinking columns whose cells don't
    // contain values to a minimum. I know there was some fitting style thing (HeaderCells
    // or something) but I fogot what it was, so this basically works fine too
    grid.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.None;
 
    // Then call BestFitColumns(), it does almost all the resizing work for you
    // well, except glueing columns
    grid.BestFitColumns();
 
    // Now that all columns are best fitted, let's see if there is still space after the last column
    var visibleColumns = grid.Columns.Where(c => c.IsVisible);
    var parentWidth = grid.Parent.Width;
    var sumVisisbleColumnsWidth = visibleColumns.Sum(c => c.Width);
    var emptySpace = parentWidth - sumVisisbleColumnsWidth;
    if (emptySpace > 0)
    {
        // If so, modify the width of our glued column
        // In this example, the last Column is glued column
        visibleColumns.Last().Width += emptySpace;
    }
}

I hope this helps some of you out.

Kind regards,
Oliver
0
Chris
Top achievements
Rank 1
answered on 07 Jul 2014, 08:07 PM
RadGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill does seem to work.  I've got Dock = Fill...columns fit the data, column headers are truncated...what else do I neeed?
0
Chris
Top achievements
Rank 1
answered on 07 Jul 2014, 08:09 PM
Sorry, post should read "Does NOT work"
0
Dimitar
Telerik team
answered on 10 Jul 2014, 09:58 AM
Hi Chris,

Thank you for writing.

When the AutoSizeColumnsMode is set to Fill the columns will fill the entire available space. And if there is no enough space for the header text it will be truncated. For such cases you can set MinWidth for the columns. For example:
void Form1_Load(object sender, EventArgs e)
{
    foreach (var item in radGridView1.Columns)
    {
        item.MinWidth = 100;
    }
}

This way when the form size is smaller that the total column mininmum size a scrollbar will appear. However I am not sure what is the exact layout behavior that you want to create. So can you please specify your exact goals? This will allow me to provide you with a proper solution for your case.

I hope this will be useful.

Regards,
Dimitar
Telerik
 
Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
 
Tags
GridView
Asked by
Waleed Seada
Top achievements
Rank 2
Answers by
Jack
Telerik team
Joshua Teter
Top achievements
Rank 1
Roland
Top achievements
Rank 1
Phillip Foster
Top achievements
Rank 1
Deborah
Top achievements
Rank 1
Emanuel Varga
Top achievements
Rank 1
Bernd Mueller
Top achievements
Rank 1
Oliver
Top achievements
Rank 1
Chris
Top achievements
Rank 1
Dimitar
Telerik team
Share this question
or